Week08_시스템 보안
Week 08 · 1과목 시스템 보안
Day 1 · 운영체제 개념 · 보안 운영체제
1-1. 운영체제는 무엇을 하는가
운영체제(OS)는 하드웨어와 사용자(응용 프로그램) 사이의 관리자다. 식당에 비유하면 손님(응용 프로그램)은 주방(하드웨어)에 직접 들어가지 않고, 지배인(OS)에게 주문한다. 지배인은 누가 먼저 요리를 받을지(CPU 스케줄링), 테이블을 어떻게 나눌지(메모리 관리), 창고 물건을 누가 꺼낼 수 있는지(파일·접근 관리), 오븐·냉장고 같은 장비를 어떻게 돌릴지(장치 관리)를 정한다.
OS의 4대 자원 관리 기능
| 기능 | 하는 일 | 보안과의 연결 |
|---|---|---|
| 프로세스 관리 | 생성·종료·스케줄링·동기화 | 권한 상승, 레이스 컨디션 |
| 메모리 관리 | 할당·회수·가상 메모리·보호 | 버퍼 오버플로, ASLR, DEP |
| 파일 관리 | 디렉터리, 권한, 소유권 | SUID, World Writable |
| 장치(I/O) 관리 | 드라이버, 인터럽트 | 커널 드라이버 루트킷 |
그 밖에 보호(Protection)·보안 기능, 네트워크 기능, 사용자 인터페이스 제공이 붙는다.
OS의 목적(성능 지표) 도 가끔 나온다.
- 처리 능력(Throughput) ↑ : 단위 시간당 처리량
- 반환 시간(Turnaround Time) ↓ : 작업 제출~결과까지
- 사용 가능도(Availability) ↑
- 신뢰도(Reliability) ↑
1-2. 커널과 쉘
┌──────────────────────────────┐
│ 사용자 / 응용 프로그램 │
├──────────────────────────────┤
│ 쉘 (명령어 해석기) │ ← bash, sh, csh, cmd, PowerShell
├──────────────────────────────┤
│ 시스템 콜 인터페이스 │ ← open(), read(), fork() ...
├──────────────────────────────┤
│ 커널 (Kernel) │ ← 프로세스·메모리·파일·장치
├──────────────────────────────┤
│ 하드웨어 (CPU·메모리·디스크) │
└──────────────────────────────┘
- 커널: OS의 심장. 부팅 후 메모리에 상주하며 자원을 직접 다룬다.
- 쉘: 사용자의 명령을 해석해 커널에 전달하는 "통역사". 커널을 조개(껍데기, shell)처럼 감싸고 있다고 해서 이름이 붙었다.
- 시스템 콜: 응용 프로그램이 커널 기능을 쓰는 유일한 공식 창구. 예: 파일을 열 때
open()→ 커널 모드로 전환 → 작업 → 사용자 모드로 복귀.
사용자 모드 vs 커널 모드 (CPU 보호 링)
Ring 0 커널 모드 (모든 명령 실행 가능)
┌──────────────┐
│ Ring 1, 2 │ (장치 드라이버용, 대부분 OS는 미사용)
│ ┌──────────┐ │
│ │ Ring 3 │ │ 사용자 모드 (특권 명령 불가)
│ └──────────┘ │
└──────────────┘
- 사용자 모드에서 특권 명령(입출력 직접 제어, 인터럽트 끄기 등)을 실행하면 예외(trap) 가 발생해 막힌다.
- 공격자의 꿈 = 사용자 모드 → 커널 모드 로 넘어가는 것(커널 익스플로잇, 커널 루트킷). 그래서 커널 루트킷이 가장 위험하다(Day 3).
커널 구조 종류
| 구조 | 설명 | 예 | 보안 관점 |
|---|---|---|---|
| 단일형(Monolithic) | 모든 기능이 커널 공간에 | 리눅스 | 빠르지만 드라이버 버그가 곧 커널 장악 |
| 마이크로커널 | 최소 기능만 커널, 나머지는 사용자 공간 서버 | Mach, QNX, seL4 | 작아서 검증 쉬움(참조 모니터 사상과 비슷) |
| 하이브리드 | 둘의 절충 | Windows NT, macOS XNU | — |
1-3. 프로세스와 스레드
- 프로그램: 디스크에 있는 실행 파일(정적).
- 프로세스: 메모리에 올라가 실행 중인 프로그램(동적). 자기만의 주소 공간, PCB(Process Control Block)를 가진다.
- 스레드: 프로세스 안의 실행 흐름 단위. 코드·데이터·힙은 공유, 스택과 레지스터는 스레드별.
PCB에 들어있는 것: PID, 프로세스 상태, 프로그램 카운터(PC), 레지스터, 스케줄링 정보(우선순위), 메모리 관리 정보, 열린 파일 목록, 소유자(UID) 등.
프로세스 상태 전이
stateDiagram-v2
state "생성 New" as New
state "준비 Ready" as Ready
state "실행 Running" as Running
state "대기 Blocked" as Blocked
state "종료 Exit" as Exit
[*] --> New
New --> Ready: 승인
Ready --> Running: 디스패치
Running --> Ready: 타임아웃
Running --> Blocked: 입출력 요청
Blocked --> Ready: 입출력 완료 wake up
Running --> Exit: 종료
Exit --> [*]- 준비(Ready) → 실행(Running) : 디스패치(Dispatch)
- 실행 → 준비 : 타임아웃(Time run out) — 선점형 스케줄링
- 실행 → 대기(Blocked/Wait) : 블록 — 입출력 요청
- 대기 → 준비 : 웨이크업(Wake up) — ⚠️ 대기에서 바로 실행으로 가지 않는다.
좀비·고아 프로세스
- 좀비(Zombie): 자식이 종료됐는데 부모가
wait()로 회수하지 않아 프로세스 테이블에 남은 상태.ps상태값Z. - 고아(Orphan): 부모가 먼저 죽은 자식 → init(systemd, PID 1)이 입양.
스케줄링 (간단히)
| 구분 | 알고리즘 | 특징 |
|---|---|---|
| 비선점 | FCFS, SJF, HRN | 실행 중이면 끝날 때까지 |
| 선점 | RR(라운드로빈), SRT, 다단계 큐 | 시간 할당량·우선순위로 뺏음 |
HRN 우선순위 = (대기시간 + 서비스시간) / 서비스시간 — 기아(starvation)를 줄인다.
1-4. 메모리 관리 기초
프로세스 메모리 구조 (Day 2 버퍼 오버플로의 출발점이니 반드시 그릴 수 있어야 한다)
높은 주소 0xFFFFFFFF
┌─────────────────────┐
│ 커널 영역 │ 사용자 접근 불가
├─────────────────────┤
│ 환경변수·argv │
├─────────────────────┤
│ 스택 (Stack) │ 지역변수, 매개변수, RET
│ ↓ 아래로 자람 │
│ │
│ (공유 라이브러리 mmap) │
│ │
│ ↑ 위로 자람 │
│ 힙 (Heap) │ malloc/new 동적 할당
├─────────────────────┤
│ BSS │ 초기화 안 된 전역/static
├─────────────────────┤
│ Data │ 초기화된 전역/static
├─────────────────────┤
│ Text (Code) │ 기계어 코드, 읽기 전용
└─────────────────────┘
낮은 주소 0x00000000
| 영역 | 저장 내용 | 생성 시점 | 특징 |
|---|---|---|---|
| Text | 실행 코드 | 컴파일 | 읽기·실행, 쓰기 불가 |
| Data | int g = 10; |
컴파일 | 읽기·쓰기 |
| BSS | int g; |
컴파일 | 0으로 초기화 |
| Heap | malloc() |
런타임 | 낮은→높은 주소 |
| Stack | 지역변수, RET, SFP | 함수 호출 | 높은→낮은 주소, LIFO |
가상 메모리: 실제 RAM보다 큰 주소 공간을 쓰는 기법. 필요한 부분만 RAM에, 나머지는 디스크(스왑)에.
- 페이징: 고정 크기(페이지)로 자름 → 외부 단편화 없음, 내부 단편화 있음.
- 세그멘테이션: 논리 단위(코드·데이터·스택)로 가변 크기 → 내부 단편화 없음, 외부 단편화 있음.
- 페이지 폴트: 필요한 페이지가 RAM에 없음 → 디스크에서 가져옴.
- 스래싱(Thrashing): 페이지 폴트가 너무 잦아 실제 작업보다 교체에 시간을 다 쓰는 상태. 해결: 워킹 셋 관리, 다중 프로그래밍 정도 낮추기.
페이지 교체 알고리즘
| 알고리즘 | 내쫓는 페이지 |
|---|---|
| FIFO | 가장 먼저 들어온 것 (벨레이디 모순 발생 가능) |
| OPT | 앞으로 가장 오래 안 쓸 것 (이론상 최적, 구현 불가) |
| LRU | 가장 오랫동안 안 쓴 것 |
| LFU | 사용 횟수가 가장 적은 것 |
| NUR | 최근 사용 안 한 것 (참조·변경 비트) |
메모리 배치 전략: 최초 적합(First Fit) / 최적 적합(Best Fit, 가장 딱 맞는 빈 공간) / 최악 적합(Worst Fit, 가장 큰 빈 공간).
1-5. 보안 커널 · 참조 모니터 · TCB
"모든 출입은 반드시 경비실을 거친다"를 운영체제에 구현한 개념이다.
- 참조 모니터(Reference Monitor): 주체(사용자·프로세스)가 객체(파일·메모리·장치)에 접근할 때 매번 보안 정책(접근 규칙)과 대조해 허용/거부를 결정하는 추상적 개념(모델).
- 보안 커널(Security Kernel): 참조 모니터를 실제로 구현한 하드웨어·펌웨어·소프트웨어.
- TCB(Trusted Computing Base): 보안 정책을 강제하는 데 관여하는 모든 보호 메커니즘의 총합(하드웨어+펌웨어+소프트웨어). TCB 안의 것이 하나라도 뚫리면 전체 보안이 무너진다. 그래서 TCB는 작을수록 좋다.
flowchart LR
S["주체
사용자·프로세스"] -->|"접근 요청"| RM{"참조 모니터
(보안 커널)"}
DB[("접근 규칙
보안 정책 DB")] --- RM
RM -->|"허용"| O["객체
파일·장치·메모리"]
RM -->|"거부"| X["차단"]
RM --> L[("감사 로그")]참조 모니터의 3대 조건
| 조건 | 의미 | 비유 |
|---|---|---|
| 완전 중재(Complete Mediation) | 모든 접근이 예외 없이·매번 검사된다. 우회 경로 없음 | 뒷문 없는 건물 |
| 격리(Isolation) | 참조 모니터 자체는 변조 불가(tamper-proof) | 경비실은 잠겨 있다 |
| 검증 가능성(Verifiability) | 작고 단순해서 올바름을 분석·테스트로 증명 가능 | 규칙서가 한 페이지 |
TCB 관련 용어
- 보안 경계(Security Perimeter): TCB와 나머지 시스템의 경계.
- 신뢰 경로(Trusted Path): 사용자와 TCB 사이의 위조 불가능한 통신 경로. 예: 윈도우 로그온 시
Ctrl+Alt+Del(SAS, Secure Attention Sequence) — 가짜 로그인 창이 이 키 조합을 가로챌 수 없다.
1-6. 보안 운영체제(Secure OS)
일반 OS는 DAC(임의적 접근통제, 소유자가 권한을 마음대로 부여)라서 root만 탈취하면 끝이다. 보안 운영체제는 커널에 보안 커널을 추가해 root조차 정책을 벗어날 수 없게 만든다.
보안 OS의 주요 기능
- 식별 및 인증 (강화된 인증)
- 강제적 접근통제(MAC) — 보안 레이블 기반
- 임의적 접근통제(DAC) 보완
- 객체 재사용 방지 — 반납된 메모리·디스크를 다음 사용자에게 주기 전 지움
- 완전한 중재, 안전한 경로
- 감사 및 감사 기록 축소
- 침입 탐지, 해킹 차단
- 최소 권한, root 권한 분할
SELinux (Security-Enhanced Linux, NSA 개발) — 리눅스 커널의 LSM(Linux Security Modules) 위에서 동작하는 MAC.
- 모든 프로세스·파일에 보안 컨텍스트(레이블) 를 붙인다:
user:role:type:level - 정책 방식: TE(Type Enforcement) 가 핵심 — "httpd_t 타입 프로세스는 httpd_sys_content_t 타입 파일만 읽을 수 있다".
- 웹 서버가 탈취돼도 SELinux 정책 밖의 파일(
/etc/shadow등)은 못 건드린다.
SELinux 3가지 모드
| 모드 | 정책 적용 | 로그 | 용도 |
|---|---|---|---|
| Enforcing | 위반 시 차단 | 기록 | 운영 (권장) |
| Permissive | 차단 안 함 | 위반만 기록 | 정책 테스트·문제 해결 |
| Disabled | 완전 비활성 | 없음 | 비권장 |
$ getenforce
Enforcing
$ sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
$ ls -Z /var/www/html/index.html
unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html
$ setenforce 0 # 일시적으로 Permissive (재부팅 시 원복)
# 영구 설정: /etc/selinux/config 의 SELINUX=enforcing
setenforce는 Enforcing ↔ Permissive 전환만 가능. Disabled 로 바꾸려면 config 수정 + 재부팅.- 위반 로그는
/var/log/audit/audit.log에type=AVC ... denied로 남는다.
AppArmor(우분투·SUSE): SELinux처럼 MAC이지만 경로(path) 기반 프로파일. 모드는 enforce / complain(=permissive와 유사).
1-7. 보안 평가 기준: TCSEC → ITSEC → CC
"이 OS·보안제품이 얼마나 믿을 만한가"를 등급으로 매기는 기준의 역사다.
flowchart LR
T["TCSEC
1985 미국 국방부
오렌지북"] --> I["ITSEC
1991 유럽
영·독·프·네"]
T --> CT["CTCPEC
캐나다"]
I --> C["CC 공통평가기준
ISO/IEC 15408"]
CT --> C
T --> CTCSEC (오렌지북) — 미 국방부, 기밀성 중심, 기능과 보증을 함께 평가
| 등급 | 이름 | 핵심 |
|---|---|---|
| D | 최소 보호 | 평가 탈락 |
| C1 | 임의적 보안 보호 | 사용자 식별·인증, DAC |
| C2 | 통제된 접근 보호 | 개별 계정 책임, 감사(Audit), 객체 재사용 방지 — 일반 상용 OS 목표 |
| B1 | 레이블된 보안 보호 | 보안 레이블 + MAC 시작 |
| B2 | 구조화된 보호 | 정형 보안 모델, 은닉 채널(저장) 분석, 신뢰 경로 |
| B3 | 보안 도메인 | 참조 모니터 요구, 보안 관리자 역할 분리 |
| A1 | 검증된 설계 | 정형적(수학적) 검증 |
암기 팁: D → C(임의적, DAC) → B(강제적, MAC) → A(검증). C는 "Choice(소유자가 선택)", B는 "Label 붙임".
ITSEC (유럽)
- 기능(F1~F10) 과 보증(E0~E6) 을 분리해 평가한 최초 기준.
- 기밀성뿐 아니라 무결성·가용성까지 고려.
CC (Common Criteria, 공통평가기준) — 국제 표준 ISO/IEC 15408, 우리나라도 CC 인증 운영.
- 핵심 용어
- TOE(Target of Evaluation): 평가 대상 제품
- PP(Protection Profile, 보호 프로파일): 제품 유형별 공통 보안 요구사항 (사용자·구매자 관점, "방화벽이라면 이 정도는 해야 한다")
- ST(Security Target, 보안 목표 명세서): 특정 제품의 보안 기능 명세 (개발자 관점, 평가의 기준 문서)
- SFR(보안 기능 요구사항) / SAR(보증 요구사항)
- EAL 1~7 (Evaluation Assurance Level)
| EAL | 이름 | 대략 대응 (TCSEC/ITSEC) |
|---|---|---|
| EAL1 | 기능 시험 | — |
| EAL2 | 구조 시험 | C1 / E1 |
| EAL3 | 방법론적 시험·점검 | C2 / E2 |
| EAL4 | 방법론적 설계·시험·검토 | B1 / E3 |
| EAL5 | 준정형적 설계·시험 | B2 / E4 |
| EAL6 | 준정형적 검증된 설계·시험 | B3 / E5 |
| EAL7 | 정형적 검증된 설계·시험 | A1 / E6 |
3기준 비교
| 구분 | TCSEC | ITSEC | CC |
|---|---|---|---|
| 지역 | 미국 | 유럽 | 국제(ISO) |
| 중점 | 기밀성 | 기밀성·무결성·가용성 | 종합 |
| 기능/보증 | 통합 | 분리 | 분리 (PP·ST) |
| 등급 | D~A1 (7) | E0~E6 | EAL1~7 |
⚠️ 시험 함정 (Day 1)
- 참조 모니터 3조건에 "가용성", "부인방지", "최소 권한" 을 끼워 넣는 오답이 많다. 정답은 완전 중재·격리(변조 방지)·검증 가능성.
- 참조 모니터 = 개념, 보안 커널 = 구현체, TCB = 보호 메커니즘 전체. 순서 바꿔 내는 문제 주의.
- TCB는 "크게 만들수록 안전"이 아니라 작을수록 검증이 쉬워 안전.
- 스택은 높은 → 낮은 주소, 힙은 낮은 → 높은 주소로 자란다. 반대로 내면 오답.
- 대기(Blocked) 상태는 입출력이 끝나면 준비(Ready) 로 간다. "대기 → 실행" 은 없다.
- TCSEC에서 MAC(레이블)이 처음 등장하는 등급은 B1, 감사(Audit)가 요구되는 최하위는 C2.
- ITSEC는 기능·보증을 분리, TCSEC는 분리하지 않음.
- PP는 제품군 공통(구현 독립적), ST는 특정 제품(구현 종속적).
- SELinux Permissive = 차단은 안 하고 로그만. "Permissive도 차단한다"는 오답.
기출 포인트 (Day 1)
- 참조 모니터의 3대 요건을 고르거나, 설명에 맞는 용어(참조 모니터/보안 커널/TCB) 고르기가 단골.
- TCSEC 각 등급 설명 → 등급 맞추기 (특히 C2, B1, B3, A1).
- CC 구성요소(PP, ST, TOE, EAL)의 의미 구분.
- 보안 OS 기능 중 해당하지 않는 것 고르기 (예: "성능 최적화"는 보안 OS 기능이 아님).
- 프로세스 상태 전이 명칭, 메모리 영역(스택·힙 방향, BSS).
확인 문제 (Day 1)
Q1. 참조 모니터(Reference Monitor)가 갖추어야 할 요건으로 옳지 않은 것은?
① 모든 접근 요청을 예외 없이 중재해야 한다 ② 자신이 변조되지 않도록 보호되어야 한다 ③ 높은 가용성을 위해 이중화되어야 한다 ④ 분석과 시험을 통해 올바름을 검증할 수 있을 만큼 작아야 한다
정답: ③
- ① 맞음: 완전 중재.
- ② 맞음: 격리(변조 방지).
- ③ 틀림: 가용성·이중화는 참조 모니터의 3조건이 아니다.
- ④ 맞음: 검증 가능성.
Q2. 보안 정책을 강제하는 데 관여하는 하드웨어, 펌웨어, 소프트웨어 보호 메커니즘 전체를 일컫는 용어는?
① 참조 모니터 ② 보안 커널 ③ TCB ④ 신뢰 경로
정답: ③
- ① 틀림: 접근 중재 개념(모델) 이다.
- ② 틀림: 참조 모니터를 구현한 핵심 부분이다. TCB의 일부.
- ③ 맞음: Trusted Computing Base = 보호 메커니즘의 총합.
- ④ 틀림: 사용자와 TCB 사이의 위조 불가능한 통신 경로.
Q3. TCSEC 등급 중 보안 레이블을 이용한 강제적 접근통제(MAC)가 처음 요구되는 등급은?
① C1 ② C2 ③ B1 ④ A1
정답: ③
- ① 틀림: C1은 임의적 접근통제(DAC) 수준.
- ② 틀림: C2는 개별 책임·감사 추가, 여전히 DAC.
- ③ 맞음: B1 "레이블된 보안 보호"부터 MAC.
- ④ 틀림: A1은 정형적 검증까지 요구하는 최상위.
Q4. SELinux의 운영 모드에 대한 설명으로 옳은 것은?
① Enforcing 모드에서는 정책 위반을 기록만 하고 차단하지 않는다 ② Permissive 모드는 정책 위반을 차단하지 않고 로그만 남긴다 ③ setenforce 0 명령으로 Disabled 모드로 전환된다 ④ Disabled 모드에서도 AVC 거부 로그가 기록된다
정답: ②
- ① 틀림: Enforcing은 차단 + 기록.
- ② 맞음.
- ③ 틀림:
setenforce 0은 Permissive 로 전환. Disabled는 설정 파일 수정 후 재부팅. - ④ 틀림: Disabled는 SELinux 자체가 꺼져 로그도 없다.
Q5. CC(공통평가기준)에서 특정 제품 유형에 대해 구현과 독립적으로 사용자 요구 보안 사항을 정의한 문서는?
① ST ② PP ③ TOE ④ EAL
정답: ②
- ① 틀림: ST는 특정 제품(구현 종속) 의 보안 목표 명세.
- ② 맞음: 보호 프로파일(PP).
- ③ 틀림: TOE는 평가 대상 그 자체.
- ④ 틀림: EAL은 보증 등급(1~7).
Q6. 프로세스 상태 전이에 대한 설명으로 옳지 않은 것은?
① 준비 → 실행 전이를 디스패치라 한다 ② 실행 중 할당 시간이 끝나면 준비 상태로 간다 ③ 입출력 요청 시 실행에서 대기 상태로 간다 ④ 입출력이 끝나면 대기 상태에서 곧바로 실행 상태로 간다
정답: ④
- ①②③ 맞음.
- ④ 틀림: 입출력 완료(Wake up) 시 준비 상태로 간다. CPU를 받으려면 다시 디스패치되어야 한다.
Day 2 · 메모리 공격 (★)
1과목에서 가장 자주, 가장 깊게 나오는 파트. 그림을 직접 그릴 수 있을 때까지 반복한다.
2-1. 함수 호출과 스택 프레임
버퍼 오버플로를 이해하려면 "함수를 호출하면 스택에 무엇이 쌓이는가"부터 알아야 한다.
main() 이 func(arg) 를 호출하면 (x86 32비트 기준, 개념 설명용):
- 인자(arg) 를 스택에 push
call명령: 돌아올 주소 = RET(Return Address) 를 push- 함수 프롤로그: 이전 함수의 기준점 SFP(Saved Frame Pointer, 이전 EBP) 를 push, EBP를 현재 위치로
- 지역 변수(버퍼) 공간 확보 (ESP를 내림)
- 함수 종료(에필로그):
leave; ret→ 스택의 RET 값을 꺼내 그 주소로 점프
비유: RET는 "책갈피"다. 다른 책(함수)을 읽으러 가면서 원래 책에 꽂아 둔 책갈피. 누가 책갈피를 몰래 다른 페이지로 옮기면, 돌아왔을 때 엉뚱한 곳을 읽게 된다.
정상 스택 프레임
높은 주소
┌──────────────────┐
│ 함수 인자 (arg) │
├──────────────────┤
│ RET (복귀 주소) │ ← 함수 끝나면 여기로 점프
├──────────────────┤
│ SFP (이전 EBP) │
├──────────────────┤ ← EBP
│ char buf[16] │ buf[15]
│ │ ...
│ │ buf[0] ← 쓰기는 여기서 시작해
└──────────────────┘ 높은 주소 방향으로 진행
낮은 주소 ← ESP
핵심 포인트: 스택은 아래(낮은 주소)로 자라지만, 배열에 데이터를 쓰는 방향은 위(높은 주소)로 간다. 그래서 buf를 넘치게 쓰면 SFP → RET 순서로 덮인다.
2-2. 스택 버퍼 오버플로
취약 코드 예시 (교육용)
#include <string.h>
void vulnerable(char *input) {
char buf[16];
strcpy(buf, input); /* 길이 검사 없음 → 취약 */
}
int main(int argc, char *argv[]) {
if (argc > 1) vulnerable(argv[1]);
return 0;
}
strcpy 는 원본 문자열의 끝(NULL)이 나올 때까지 무조건 복사한다. 목적지 크기를 모른다.
오버플로 전/후 비교
[정상 입력 "AAAA"]
┌──────────────────┐
│ arg │
├──────────────────┤
│ RET = 0x08048456 │ 정상 복귀 주소
├──────────────────┤
│ SFP │
├──────────────────┤
│ buf: AAAA\0 │
└──────────────────┘
[과도한 입력 'A'x20 + 주소 4바이트]
┌──────────────────┐
│ arg │
├──────────────────┤
│ RET = 공격자 주소 │ ★ 변조됨
├──────────────────┤
│ AAAA (SFP 덮임) │
├──────────────────┤
│ AAAAAAAAAAAAAAAA │ buf 16B 가득
└──────────────────┘
→ 함수 종료 시 ret 이
공격자가 지정한 곳으로 점프
공격 흐름 (개념)
- 공격자는 버퍼 크기 + SFP 크기만큼 채운 뒤 RET 위치에 원하는 주소를 넣는다.
- 그 주소는 보통 공격자가 메모리 어딘가(버퍼 자체, 환경변수 등)에 넣어 둔 쉘코드(쉘을 띄우는 기계어)의 위치.
- 대상 프로그램이 SUID root 라면 띄워진 쉘도 root 권한 → 권한 상승.
- 주소를 정확히 몰라도 되도록 쉘코드 앞을 NOP(0x90) 썰매(NOP sled) 로 채우는 기법이 알려져 있다.
그래서 SUID 파일 점검(Day 4)과 버퍼 오버플로는 한 세트다. 취약한 SUID root 프로그램 = root로 가는 문.
2-3. 힙 버퍼 오버플로
힙은 malloc() 으로 동적 할당되는 영역이다. 힙에는 RET가 없으므로 다른 것을 노린다.
- 인접한 힙 청크의 데이터(다른 변수, 구조체 안의 함수 포인터)를 덮어씀
- 힙 관리 메타데이터(청크 헤더의 크기·연결 포인터)를 조작해 해제(
free) 시점에 임의 메모리 쓰기를 유도 - 관련 취약점: UAF(Use After Free) — 해제한 메모리를 계속 사용, Double Free — 같은 메모리를 두 번 해제
힙 (낮은 → 높은 주소로 할당)
┌──────────┬──────────────┐
│ 청크A헤더 │ char name[32]│
├──────────┼──────────────┤
│ 청크B헤더 │ 함수포인터 fp │
└──────────┴──────────────┘
name 이 넘치면 → 청크B 헤더·fp 덮어씀
→ 나중에 fp() 호출 시 엉뚱한 곳 실행
| 비교 | 스택 BOF | 힙 BOF |
|---|---|---|
| 대상 영역 | 스택(지역변수) | 힙(동적 할당) |
| 주된 목표 | RET, SFP | 인접 데이터, 함수 포인터, 청크 메타데이터 |
| 난이도 | 상대적으로 쉬움 | 어려움(힙 구조 이해 필요) |
| 대표 방어 | Canary, Stack Shield | 힙 메타데이터 무결성 검사, ASLR, DEP |
2-4. 취약 함수 vs 안전 함수
| 취약 함수 | 문제 | 안전한 대안 |
|---|---|---|
strcpy(d, s) |
길이 검사 없음 | strncpy, strlcpy, strcpy_s |
strcat(d, s) |
길이 검사 없음 | strncat, strlcat |
gets(buf) |
입력 길이 제한 불가 (C11에서 제거) | fgets(buf, size, stdin) |
sprintf |
결과 길이 제한 없음 | snprintf |
scanf("%s") |
길이 무제한 | scanf("%15s", buf) (폭 지정) |
vsprintf |
동일 | vsnprintf |
getwd |
버퍼 크기 미지정 | getcwd(buf, size) |
안전 코드 예시
#include <stdio.h>
#include <string.h>
void safer(const char *input) {
char buf[16];
/* 방법 1: strncpy - n바이트만 복사, NULL 종료 보장 안 됨 */
strncpy(buf, input, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0'; /* 직접 NULL 종료 */
/* 방법 2: snprintf - 항상 NULL 종료 보장 */
snprintf(buf, sizeof(buf), "%s", input);
}
void read_line(void) {
char line[64];
if (fgets(line, sizeof(line), stdin) != NULL) { /* gets 대신 */
line[strcspn(line, "\n")] = '\0'; /* 개행 제거 */
}
}
⚠️
strncpy는 원본이 n 이상이면 NULL 종료 문자를 붙이지 않는다. 그래서 마지막 바이트를 직접'\0'으로 채워야 한다. "strncpy를 쓰면 완벽히 안전"은 오답 포인트.
2-5. 방어 기법 ① 스택 보호: Canary · Stack Guard · Stack Shield
Stack Guard / 카나리(Canary)
- 탄광의 카나리아 새(유독가스에 먼저 쓰러져 위험을 알림)에서 이름이 왔다.
- 지역변수(버퍼)와 RET 사이에 검사값(카나리)을 넣고, 함수가 리턴하기 직전에 값이 바뀌었는지 확인. 바뀌었으면 프로그램을 강제 종료.
- RET를 덮으려면 반드시 그 앞의 카나리도 덮어야 하므로 탐지된다.
┌──────────────────┐
│ RET │
├──────────────────┤
│ SFP │
├──────────────────┤
│ ★ CANARY ★ │ ← 리턴 직전 검사:
├──────────────────┤ 원래 값과 같은가?
│ buf[16] │
└──────────────────┘
넘치면 카나리부터 깨진다 → 종료
* 교재에 따라 "RET 앞"(SFP 포함 위치)로 그림
카나리 종류
| 종류 | 값 | 원리 |
|---|---|---|
| Terminator | 0x00(NULL), 0x0d(CR), 0x0a(LF), 0xff(EOF) |
문자열 함수는 NULL·개행에서 복사를 멈추므로 카나리를 그대로 재현 불가 |
| Random | 실행 시 무작위 값 | 공격자가 값 예측 불가 |
| Random XOR | 랜덤값 XOR 제어 데이터(RET 등) | RET만 바꿔도 불일치 |
- GCC 옵션:
-fstack-protector,-fstack-protector-strong,-fstack-protector-all - 탐지 시 메시지:
*** stack smashing detected ***: terminated
Stack Shield
- 함수 시작 시 RET 값을 별도의 안전한 영역(Global Ret Stack)에 복사해 두고, 함수 종료 시 스택의 RET와 비교. 다르면 종료(또는 저장해 둔 값으로 복구).
- 카나리가 "울타리를 쳐서 침입 감지"라면, Stack Shield는 "원본 사본을 금고에 보관해 대조".
2-6. 방어 기법 ② ASLR · DEP/NX
ASLR (Address Space Layout Randomization)
- 프로그램이 실행될 때마다 스택·힙·공유 라이브러리(PIE면 코드까지) 주소를 무작위로 배치.
- 공격자는 RET에 "어디로 점프할지" 주소를 넣어야 하는데, 그 주소가 매번 바뀌니 맞히기 어렵다.
실행 1회차 실행 2회차
┌───────────┐ ┌───────────┐
│스택 0xbf8..│ │스택 0xbfd..│ ← 매번 다름
│libc 0xb75..│ │libc 0xb7e..│ ← 매번 다름
│힙 0x09a.. │ │힙 0x08c.. │ ← 매번 다름
│코드 0x080.. │ │코드 0x080.. │ ← PIE 아니면 고정
└───────────┘ └───────────┘
$ cat /proc/sys/kernel/randomize_va_space
2
# 0 = 비활성 (취약)
# 1 = 스택, 라이브러리(mmap), vdso 랜덤화
# 2 = 1 + 힙(brk) 랜덤화 (기본값, 권장)
$ sysctl -w kernel.randomize_va_space=2
- 코드(Text) 영역까지 랜덤화하려면 PIE(Position Independent Executable)로 컴파일해야 한다(
-fPIE -pie). - 윈도우: 실행 파일이
/DYNAMICBASE로 빌드되어야 ASLR 적용.
DEP / NX bit
- NX(No-eXecute) bit: CPU 페이지 테이블의 비트로 "이 페이지는 데이터일 뿐 실행 불가"를 표시. AMD는 NX, Intel은 XD(eXecute Disable).
- DEP(Data Execution Prevention): 윈도우의 이름. 하드웨어 DEP(NX 사용) + 소프트웨어 DEP(SafeSEH).
- 효과: 스택·힙에 쉘코드를 넣어도 실행이 안 된다 → 고전적 "스택에 쉘코드 + RET로 점프" 공격 무력화.
- 원칙: W^X (Write XOR Execute) — 쓸 수 있는 메모리는 실행 불가, 실행 가능한 메모리는 쓰기 불가.
2-7. 방어 우회 개념: RTL · ROP
"스택에서 실행이 안 되면, 이미 실행 가능한 코드를 재사용하자"는 발상이다.
RTL (Return-to-Libc)
- RET를 쉘코드가 아니라 libc 안의 함수(예:
system()) 주소로 바꾼다. 인자로 쓸 문자열 주소도 스택에 배치. - libc 코드는 원래 실행 가능한 영역이므로 NX/DEP를 우회.
- 약점: libc 주소를 알아야 함 → ASLR 이 대응책.
ROP (Return-Oriented Programming)
- 기존 코드 곳곳의
ret으로 끝나는 짧은 명령 조각(가젯, gadget)을 찾아, 스택에 가젯 주소를 줄줄이 쌓아 조각들을 이어 붙여 원하는 동작을 만든다. - 비유: 신문 글자를 오려 붙여 편지를 만드는 것. 새 글자(코드)를 쓰지 않고 기존 글자만 사용.
- RTL의 일반화 버전. NX 우회, ASLR은 주소 정보 유출과 결합해 우회.
- 대응: ASLR+PIE, CFI(Control-Flow Integrity), 섀도 스택(Intel CET), RELRO.
flowchart TD
A["고전 BOF
스택에 쉘코드"] -->|"방어: NX/DEP"| B["RTL
libc 함수 재사용"]
B -->|"방어: ASLR"| C["ROP + 주소 유출
가젯 연결"]
C -->|"방어: CFI·섀도 스택"| D["계속되는 공방"]
A -->|"방어: Canary"| E["카나리 유출 시도"]방어 기법 총정리
| 기법 | 막는 것 | 원리 | 우회 개념 |
|---|---|---|---|
| Canary | RET 덮어쓰기 | RET 앞 검사값 | 카나리 값 유출 |
| Stack Shield | RET 변조 | RET 사본 대조 | 함수 포인터 등 다른 대상 |
| ASLR | 주소 예측 | 주소 무작위화 | 주소 유출, 반복 시도 |
| DEP/NX | 스택·힙 코드 실행 | 실행 금지 비트 | RTL, ROP |
| PIE | 코드 주소 예측 | 코드도 재배치 | 주소 유출 |
| RELRO | GOT 덮어쓰기 | GOT 읽기 전용화 | — |
| 안전 함수 | 근본 원인 | 길이 검사 | — |
2-8. 포맷 스트링 공격
printf 계열 함수는 첫 번째 인자(포맷 문자열)를 해석해 %d, %s 를 만날 때마다 스택에서 다음 인자를 꺼낸다. 그런데 사용자 입력을 포맷 문자열 자리에 그대로 넣으면, 사용자가 %x 를 넣는 순간 printf 는 존재하지 않는 인자를 찾아 스택을 읽어 버린다.
/* 취약 */
void log_msg(char *user_input) {
printf(user_input); /* 사용자가 포맷을 조종 */
}
/* 안전 */
void log_msg_safe(char *user_input) {
printf("%s", user_input); /* 입력은 단지 '데이터' */
}
스택 읽기 그림 (개념)
printf(buf), buf = "%x %x %x"
┌──────────────────┐
│ buf 주소 (포맷) │ ← 실제 유일한 인자
├──────────────────┤
│ 0xbffff6a0 │ ← 1번째 %x 가 읽음
├──────────────────┤
│ 0x00000010 │ ← 2번째 %x
├──────────────────┤
│ 0x41414141 │ ← 3번째 %x
└──────────────────┘ (지역변수 내용 노출)
출력: bffff6a0 10 41414141
→ 메모리 내용 유출
주요 포맷 지정자와 악용
| 지정자 | 정상 의미 | 공격 시 효과 |
|---|---|---|
%x |
16진수 출력 | 스택 값 읽기(정보 유출) |
%s |
주소가 가리키는 문자열 | 임의 주소 읽기, 잘못된 주소면 크래시(DoS) |
%n |
지금까지 출력한 바이트 수를 해당 주소에 기록 | 메모리 쓰기 → RET·GOT 변조 |
%hn |
%n 의 2바이트 버전 |
정밀한 쓰기 |
- 취약 함수:
printf,fprintf,sprintf,snprintf,syslog등 포맷을 받는 모든 함수. - 대응
- 포맷 문자열을 상수로 고정:
printf("%s", buf) - 컴파일러 경고:
-Wformat -Wformat-security _FORTIFY_SOURCE로 위험한%n사용 제한
- 포맷 문자열을 상수로 고정:
2-9. 레이스 컨디션 (Race Condition)
두 프로세스가 같은 자원을 두고 "경주"할 때, 실행 순서·타이밍에 따라 결과가 달라지는 취약점이다. 보안에서는 주로 TOCTOU(Time Of Check to Time Of Use) — "검사한 시점"과 "사용한 시점" 사이의 틈을 노린다.
전형적 시나리오: SUID root 프로그램의 임시 파일
- root 권한으로 동작하는 프로그램이
/tmp/report.tmp라는 예측 가능한 이름의 임시 파일을 만든다. - 공격자는 그 순간을 노려 같은 이름으로 심볼릭 링크
/tmp/report.tmp → /etc/shadow를 만든다. - 프로그램은 링크인지 모르고 root 권한으로 파일에 쓴다 → 실제로는
/etc/shadow가 덮어써짐.
타임라인
시간 ↓
[SUID 프로그램(root)] [공격자(일반 사용자)]
① /tmp/x 검사 OK
│
│ ② rm /tmp/x
│ ③ ln -s /etc/passwd /tmp/x
│ ↑ 이 틈(window)!
▼
④ /tmp/x 열고 쓰기
→ 링크를 따라가
/etc/passwd 를
root 권한으로 수정
sequenceDiagram
participant P as SUID 프로그램(root)
participant FS as /tmp
participant A as 공격자
P->>FS: 1. 파일 존재·권한 검사 (Check)
A->>FS: 2. 같은 이름을 심볼릭 링크로 교체
P->>FS: 3. 파일 열고 쓰기 (Use)
FS-->>P: 실제로는 링크 대상 파일에 기록취약 vs 안전 코드
/* 취약: 예측 가능한 이름 + 검사와 사용 분리 */
if (access("/tmp/app.tmp", F_OK) != 0) { /* Check */
FILE *fp = fopen("/tmp/app.tmp", "w"); /* Use */
/* ... */
}
/* 안전: mkstemp
- 무작위 이름
- 원자적 생성(O_CREAT|O_EXCL)
- 권한 0600 */
#include <stdlib.h>
#include <unistd.h>
char tmpl[] = "/tmp/appXXXXXX"; /* XXXXXX 가 랜덤으로 치환 */
int fd = mkstemp(tmpl);
if (fd != -1) {
/* fd 로만 작업 */
unlink(tmpl); /* 이름은 바로 제거 */
close(fd);
}
대응 방법
- 임시 파일 이름을 예측 불가능하게(
mkstemp,tmpfile) —mktemp,tmpnam은 이름만 만들고 생성은 따로라 여전히 틈이 있다. - 생성은 원자적으로:
open(path, O_CREAT | O_EXCL, 0600)(이미 있으면 실패). - 심볼릭 링크 따라가기 금지:
O_NOFOLLOW,lstat()으로 링크 여부 확인. - 경로 기반 재검사 대신 파일 디스크립터 기반(
fstat)으로 처리. /tmp에 Sticky Bit(drwxrwxrwt) — 남의 파일 삭제 불가.- 적절한 umask(022 또는 077).
- 리눅스 커널 보호:
fs.protected_symlinks=1,fs.protected_hardlinks=1.
2-10. 정수 오버플로 (Integer Overflow)
정수형 변수는 담을 수 있는 범위가 정해져 있다. 범위를 넘으면 값이 뒤집힌다(wrap-around). 자동차 주행거리계가 999999 다음에 000000이 되는 것과 같다.
| 자료형 | 범위 | 넘칠 때 |
|---|---|---|
unsigned char |
0 ~ 255 | 255 + 1 → 0 |
signed char |
-128 ~ 127 | 127 + 1 → -128 (구현 의존) |
int (32bit) |
약 -21억 ~ +21억 | 최댓값 + 1 → 음수 |
unsigned int |
0 ~ 약 42억 | 0 - 1 → 4,294,967,295 |
보안 문제가 되는 패턴
/* 취약: 부호 있는 길이 검사 후 부호 없는 크기로 사용 */
void copy_data(char *src, int len) {
char buf[100];
if (len < 100) { /* len = -1 이면 통과! */
memcpy(buf, src, len); /* size_t(부호 없음)로 해석
→ 매우 큰 수 → BOF */
}
}
/* 안전: 부호 없는 타입 + 범위 검사 */
void copy_data_safe(const char *src, size_t len) {
char buf[100];
if (len > 0 && len < sizeof(buf)) {
memcpy(buf, src, len);
}
}
- 또 다른 패턴:
malloc(count * size)에서 곱셈이 넘쳐 아주 작은 버퍼가 할당 → 이후 복사에서 힙 오버플로. - 정수 오버플로 자체보다 그 결과로 생기는 버퍼 오버플로가 실질적 피해.
- 대응: 연산 전 범위 검사, 부호 없는 타입 일관 사용, 오버플로 검사 연산 함수,
calloc사용.
⚠️ 시험 함정 (Day 2)
- 스택 BOF가 덮는 핵심은 RET(리턴 주소). "힙의 RET를 덮는다" 같은 표현은 오답.
strncpy는 길이 제한은 하지만 NULL 종료를 보장하지 않는다.gets의 대체는fgets. 방향을 거꾸로 낸 보기 주의.- NX/DEP를 우회하는 것은 RTL/ROP, ASLR은 주소 랜덤화. "ASLR이 실행을 금지한다"는 오답.
- Stack Shield는 RET 복사본 비교, Stack Guard는 카나리 값 비교. 둘을 바꿔 내는 문제 단골.
- 포맷 스트링에서 쓰기 는
%n, 읽기는%x/%s. - 레이스 컨디션 대응으로 "임시 파일 이름을 고정해서 관리" 는 오답(오히려 취약).
mktemp(이름만 생성)와mkstemp(안전한 생성까지)는 다르다.- 정수 오버플로는 그 자체로 코드 실행이 아니라 길이 검사를 무력화해 BOF로 이어지는 경우가 많다.
기출 포인트 (Day 2)
- 스택 구조 그림에서 버퍼 → SFP → RET 순서와 덮이는 대상 고르기.
- 취약 함수 ↔ 안전 함수 짝짓기, "안전하지 않은 함수가 아닌 것" 고르기.
- 방어 기법 설명 → 이름 맞추기(Canary/Stack Shield/ASLR/NX). 실기에서는 "원리"를 서술형으로 묻는다.
printf(buf)코드를 주고 취약점명(포맷 스트링)과 수정 코드 묻기.- 임시 파일 + 심볼릭 링크 시나리오 → 레이스 컨디션, 대응책 서술.
randomize_va_space값의 의미.
확인 문제 (Day 2)
Q1. 스택 버퍼 오버플로 공격에서 공격자가 프로그램의 실행 흐름을 바꾸기 위해 주로 덮어쓰는 값은?
① 힙 청크의 크기 정보 ② 함수의 리턴 주소(RET) ③ BSS 영역의 전역 변수 ④ 코드 영역의 명령어
정답: ②
- ① 틀림: 힙 오버플로의 대상.
- ② 맞음: 함수 종료 시
ret명령이 이 값으로 점프. - ③ 틀림: 스택 BOF와 무관한 영역.
- ④ 틀림: 코드 영역은 일반적으로 쓰기 금지.
Q2. 함수 시작 시 리턴 주소를 별도의 안전한 메모리 영역에 복사해 두었다가 함수 종료 시 비교하는 방어 기법은?
① Stack Guard ② Stack Shield ③ ASLR ④ NX bit
정답: ②
- ① 틀림: 카나리(검사값)를 RET 앞에 둬서 변조를 탐지.
- ② 맞음: Global Ret Stack에 RET 사본을 저장해 대조.
- ③ 틀림: 주소 공간 무작위화.
- ④ 틀림: 데이터 영역 실행 금지.
Q3. NX(DEP)가 적용된 환경에서 스택의 코드 실행 제한을 우회하기 위해 사용되는 기법으로 가장 적절한 것은?
① NOP sled ② Return-to-Libc ③ 힙 스프레이 ④ Terminator Canary
정답: ②
- ① 틀림: 쉘코드 위치 오차를 흡수하는 기법일 뿐, 스택이 실행 불가면 소용없다.
- ② 맞음: 이미 실행 가능한 libc 함수로 점프.
- ③ 틀림: 힙에 데이터를 대량으로 뿌리는 기법. NX 우회가 핵심이 아니다.
- ④ 틀림: 카나리는 방어 기법.
Q4. 다음 코드의 취약점과 수정 방법이 올바르게 짝지어진 것은?
void f(char *s) { printf(s); }
① 레이스 컨디션 – mkstemp 사용 ② 포맷 스트링 – printf("%s", s) ③ 정수 오버플로 – size_t 사용 ④ 힙 오버플로 – free 후 NULL 대입
정답: ②
- 사용자 입력이 포맷 문자열로 해석되어
%x로 읽기,%n으로 쓰기가 가능하다. 포맷을 상수로 고정하면 해결. - ①③④는 각각 다른 취약점의 대응.
Q5. 레이스 컨디션 공격에 대한 대응으로 옳지 않은 것은?
① 임시 파일 생성 시 mkstemp()를 사용한다 ② 임시 파일 이름을 프로그램마다 고정된 이름으로 정해 관리한다 ③ 파일 생성 시 O_CREAT와 O_EXCL 플래그를 함께 사용한다 ④ 심볼릭 링크 여부를 확인하고 따라가지 않도록 한다
정답: ②
- ② 틀림: 고정 이름은 예측 가능해서 공격자가 미리 심볼릭 링크를 만들 수 있다.
- ①③④ 맞음.
Q6. 리눅스에서 /proc/sys/kernel/randomize_va_space 값이 2 일 때의 의미로 옳은 것은?
① ASLR 비활성 ② 스택만 랜덤화 ③ 스택·라이브러리·힙까지 랜덤화 ④ NX bit 활성화
정답: ③
- 0: 비활성, 1: 스택·mmap(라이브러리)·vdso, 2: 1 + 힙(brk). NX와는 별개 설정이다.
Day 3 · 악성코드 · 사회공학 · 엔드포인트 보안
3-1. 악성코드 분류의 기준
악성코드(Malware)를 구분하는 두 가지 핵심 질문만 기억하면 대부분 풀린다.
- 스스로 복제(증식)하는가?
- 숙주(다른 파일)가 필요한가, 독립 실행되는가?
flowchart TD
M["악성코드"] --> R{"자기 복제?"}
R -->|"예"| H{"숙주 파일 필요?"}
H -->|"예"| V["바이러스"]
H -->|"아니오, 독립 실행"| W["웜"]
R -->|"아니오"| N["비복제형"]
N --> T["트로이목마
정상 위장"]
N --> B["백도어
인증 우회 통로"]
N --> RK["루트킷
은닉·권한 유지"]
N --> RS["랜섬웨어
암호화·금전 요구"]
N --> SP["스파이웨어·키로거
정보 수집"]
N --> LB["논리 폭탄
조건부 실행"]
N --> BOT["봇
원격 조종"]랜섬웨어·봇은 웜 기능(자기 전파)을 결합한 변종도 많다(예: 2017 WannaCry는 SMB 취약점으로 전파하는 랜섬웨어 + 웜). 시험에서는 "기본 정의"로 판단한다.
3-2. 바이러스
정의: 다른 프로그램(숙주)에 자신의 코드를 삽입(기생) 해, 숙주가 실행될 때 함께 실행되며 다른 파일로 자기 복제하는 악성코드. 사람 바이러스가 세포 없이 증식 못 하듯, 숙주가 필요하다.
감염 위치에 따른 분류
| 유형 | 감염 대상 | 예 |
|---|---|---|
| 부트 바이러스 | 부트 섹터, MBR | 브레인(Brain), 미켈란젤로 |
| 파일 바이러스 | 실행 파일(COM, EXE) | 예루살렘, CIH(체르노빌) |
| 부트/파일 바이러스 | 둘 다 | 침입자, 나타스 |
| 매크로 바이러스 | 문서 파일의 매크로(Word, Excel) | 멜리사(Melissa), 라룩스 |
파일 감염 방식: 겹쳐쓰기형(원본 파괴), 기생형(앞·뒤에 붙음, 원본 유지), 산란형(같은 이름의 다른 확장자 파일 생성, 예: COM이 EXE보다 먼저 실행되는 점 악용), 연결형(디렉터리 정보 조작).
바이러스 세대 구분 (진화 = 백신을 피하는 방향)
| 세대 | 이름 | 특징 | 백신 회피 원리 |
|---|---|---|---|
| 1세대 | 원시형 | 단순 구조, 고정 코드 | 없음 (시그니처로 쉽게 탐지) |
| 2세대 | 암호형 | 몸체를 암호화, 실행 시 복호화 루틴으로 풀림 | 몸체 시그니처 숨김 (단, 복호화 루틴은 고정) |
| 3세대 | 은폐형(스텔스) | 감염 사실을 숨김: 파일 크기·날짜를 원래대로 보여 줌 | 시스템 호출 가로채 감염 전 정보 반환 |
| 4세대 | 갑옷형(Armor) | 다양한 암호화·난독화로 분석 자체를 어렵게 함. 다형성(Polymorphic) 바이러스 포함: 감염 때마다 복호화 루틴까지 변형 | 고정 시그니처 자체가 없음 |
| 5세대 | 매크로 | 문서의 매크로 기능 이용, 플랫폼 독립적 | 실행 파일이 아니라 문서로 전파 |
- 다형성(Polymorphic) vs 변성(Metamorphic): 다형성은 암호화 키·복호화 루틴을 바꿔 겉모습을 바꾸고, 변성은 코드 자체(명령 순서·구조)를 재작성한다.
- 교재에 따라 4세대를 "다형성"으로 바로 적기도 한다. 핵심은 "모양이 매번 바뀌어 시그니처 탐지를 피함".
3-3. 웜 · 트로이목마 · 백도어
웜(Worm)
- 독립 실행형, 숙주 불필요. 네트워크(취약점, 이메일, 공유 폴더, USB)를 통해 스스로 전파.
- 피해: 대량 트래픽으로 네트워크 마비(가용성 침해).
- 사례: 모리스 웜(1988, 최초급 인터넷 웜), 코드레드(IIS 버퍼 오버플로), 슬래머(SQL Slammer, 2003 1·25 인터넷 대란, UDP 1434), 블래스터(RPC DCOM), 님다(복합 전파), 콘피커.
트로이목마(Trojan Horse)
- 유용한 프로그램(게임, 크랙, 유틸리티)으로 위장해 사용자가 직접 설치하게 만듦.
- 자기 복제하지 않는다 ← 바이러스·웜과의 결정적 차이.
- 주로 백도어 설치, 정보 탈취, RAT(Remote Access Trojan, 원격 제어) 역할.
백도어(Backdoor, Trapdoor)
- 정상 인증 절차를 우회해 시스템에 접근하는 비밀 통로.
- 개발자가 디버깅용으로 남긴 것(유지보수 훅)일 수도, 공격자가 침입 후 재접속용으로 심은 것일 수도 있다.
- 탐지 단서: 열린 포트(
netstat -an,ss -tulpn), 알 수 없는 프로세스, 새로 생긴 계정·SUID 파일, 변조된 바이너리(무결성 점검).
| 비교 | 바이러스 | 웜 | 트로이목마 |
|---|---|---|---|
| 자기 복제 | O | O | X |
| 숙주 필요 | O | X (독립) | X (독립 실행 파일) |
| 전파 수단 | 감염 파일 실행·공유 | 네트워크 자동 전파 | 사용자가 속아서 설치 |
| 주 피해 | 파일 손상 | 네트워크 부하 | 정보 유출, 원격 제어 |
3-4. 루트킷 (Rootkit)
이름 그대로 "root 권한을 유지하기 위한 도구 모음(kit)". 침입에 성공한 공격자가 흔적을 숨기고(은닉), 다시 들어올 수 있게(백도어) 하며, 관리자 권한을 유지하는 것이 목적.
주요 기능: 프로세스·파일·네트워크 연결 숨기기, 로그 삭제·변조, 백도어, 스니퍼, 키로거.
┌───────────────────────────────┐
│ 사용자 공간 │
│ ls, ps, netstat ← ①사용자 모드 │
│ 루트킷이 │
│ 바이너리 교체 │
├───────────────────────────────┤
│ 시스템 콜 테이블 ← ②커널 모드 │
│ 커널 모듈(LKM) 루트킷이 │
│ 후킹·조작 │
└───────────────────────────────┘
| 구분 | 사용자 모드(User-mode) 루트킷 | 커널 모드(Kernel-mode) 루트킷 |
|---|---|---|
| 동작 위치 | 사용자 공간 (Ring 3) | 커널 공간 (Ring 0) |
| 방법 | ls, ps, netstat, login 같은 시스템 바이너리를 변조본으로 교체, 라이브러리 후킹 |
LKM(적재 가능 커널 모듈) 로 커널에 삽입, 시스템 콜 테이블 후킹, DKOM(커널 객체 직접 조작) |
| 탐지 | 상대적으로 쉬움 — 무결성 점검(Tripwire, 해시 비교) 으로 바이너리 변조 발견 | 매우 어려움 — 커널이 거짓말을 하므로 그 위의 모든 도구가 속음 |
| 예 | lrk(Linux RootKit) 계열 | knark, adore 계열 |
- 더 깊은 단계: 부트킷(MBR/VBR·부트로더 감염, OS보다 먼저 실행), 펌웨어(UEFI) 루트킷, 하이퍼바이저(VM 기반) 루트킷.
- 탐지 도구: chkrootkit, rkhunter(Rootkit Hunter), 윈도우는 GMER 등. 근본적으로는 신뢰할 수 있는 외부 매체로 부팅해 오프라인 검사, 혹은 메모리 포렌식.
- 대응: 루트킷이 의심되면 "청소"보다 재설치가 원칙(커널을 믿을 수 없으므로).
3-5. 랜섬웨어 · 봇넷 · 파일리스 · 기타
랜섬웨어(Ransomware) = Ransom(몸값) + Software
- 파일을 암호화(보통 대칭키로 파일 암호화 → 그 대칭키를 공격자의 공개키로 암호화)해 복호화 대가로 암호화폐 요구.
- 최근 형태: 이중 갈취(암호화 + 데이터 유출 협박), RaaS(Ransomware as a Service, 서비스형 랜섬웨어).
- 대응: 오프라인·분리 백업(3-2-1 규칙), 패치, 매크로 차단, 최소 권한, EDR.
- 3-2-1: 사본 3개, 매체 2종류, 1개는 외부(오프사이트·오프라인).
봇(Bot) / 봇넷(Botnet)
- 감염된 PC(좀비)가 C&C(Command & Control) 서버의 명령을 받아 움직임.
- 용도: DDoS, 스팸 발송, 추가 악성코드 배포, 크리덴셜 스터핑.
- C&C 구조: 중앙집중형(IRC, HTTP) → 탐지·차단 쉬움 / P2P형 → 차단 어려움.
- 탐지 회피: Fast-flux(IP 빠르게 교체), DGA(도메인 생성 알고리즘).
[공격자/봇마스터]
│
[C&C 서버]
┌──────┼──────┐
[봇] [봇] [봇] ← 감염 PC(좀비)
└──────┼──────┘
▼
[공격 대상] ← DDoS
파일리스(Fileless) 악성코드
- 디스크에 실행 파일을 남기지 않고 메모리에서만 동작하거나, 정상 시스템 도구(PowerShell, WMI, mshta, rundll32 등)를 악용 = LotL(Living off the Land, 현지 자원 활용).
- 레지스트리 값에 스크립트를 저장해 지속성 확보하기도 함.
- 파일 기반 시그니처 백신으로 탐지 어려움 → 행위 기반 탐지(EDR), PowerShell 로깅(스크립트 블록 로깅), AMSI, 애플리케이션 제어가 대응책.
기타
| 유형 | 설명 |
|---|---|
| 스파이웨어 | 사용자 몰래 정보 수집(브라우징, 개인정보) |
| 키로거 | 키보드 입력 기록 → 계정 탈취 |
| 애드웨어 | 광고 강제 노출 |
| 논리 폭탄(Logic Bomb) | 특정 조건(날짜, 특정 사용자 삭제 등) 충족 시 실행. 퇴사자가 심는 사례 |
| 드로퍼(Dropper) | 내부에 악성코드를 품고 있다가 설치 |
| 다운로더 | 외부에서 악성코드를 내려받아 설치 |
| 익스플로잇 킷 | 웹 접속자의 브라우저·플러그인 취약점을 자동 공격 |
| 혹스(Hoax) | 거짓 바이러스 경고로 불안 조장 (실제 코드 없음) |
| 크립토재킹 | 피해자 자원으로 암호화폐 채굴 |
3-6. 악성코드 분석: 정적 · 동적 · 샌드박스
| 구분 | 정적 분석 (Static) | 동적 분석 (Dynamic) |
|---|---|---|
| 실행 여부 | 실행하지 않음 | 실제 실행(격리 환경) |
| 기초 수준 | 해시 조회(VirusTotal), 문자열 추출(strings), PE 헤더·임포트 함수 확인, 패킹 여부(PEiD 등) | 프로세스·파일·레지스트리·네트워크 변화 관찰(Process Monitor, Process Explorer, Wireshark, Regshot) |
| 고급 수준 | 디스어셈블·디컴파일(IDA, Ghidra) | 디버깅(x64dbg, OllyDbg, WinDbg)으로 단계별 실행 |
| 장점 | 안전, 전체 코드 경로 파악 | 실제 행위 빠르게 파악, 난독화 영향 적음 |
| 단점 | 패킹·난독화에 약함, 시간 소요 | 감염 위험, 안티VM·안티디버깅·조건부 실행 시 행위 안 보임 |
분석 절차 (보통 순서)
flowchart LR
A["1 기초 정적
해시·문자열·PE"] --> B["2 기초 동적
샌드박스 실행·행위 관찰"]
B --> C["3 고급 정적
디스어셈블"]
C --> D["4 고급 동적
디버깅"]
D --> E["IoC 추출
해시·IP·도메인"]- 패킹(Packing): 실행 파일을 압축·암호화해 코드를 숨김(UPX 등). 정적 분석 전 언패킹 필요.
- 샌드박스: 외부와 격리된 가상 환경에서 의심 파일을 실행해 행위를 자동 분석(예: Cuckoo Sandbox 계열). 네트워크 보안 장비의 APT 대응 솔루션도 이 방식.
- 회피 기법: VM 흔적(VMware 도구, 특정 MAC 주소) 탐지, 실행 지연(sleep), 사용자 상호작용 대기.
- IoC(Indicators of Compromise, 침해 지표): 파일 해시, C&C IP·도메인, 레지스트리 키, 뮤텍스 이름 등. 공유해 다른 조직이 탐지에 활용.
- YARA: 문자열·바이트 패턴 규칙으로 악성코드를 분류·탐지하는 도구.
3-7. 탐지 기법과 엔드포인트 보안 솔루션
백신의 탐지 방식
| 방식 | 원리 | 장점 | 단점 |
|---|---|---|---|
| 시그니처(패턴) 기반 | 알려진 악성코드의 고유 바이트 패턴·해시와 비교 | 오탐 낮음, 빠름 | 신종·변종(제로데이) 탐지 불가 |
| 휴리스틱 | 의심스러운 코드 특징·명령 조합에 점수 | 변종 일부 탐지 | 오탐 증가 |
| 행위 기반 | 실행 중 행위(대량 파일 암호화, 자기 복제) 감시 | 신종·파일리스 대응 | 실행 후 탐지, 오탐 |
| 평판 기반 | 파일·URL의 유포 규모·나이 | 빠른 판단 | 신규 정상 파일 오탐 |
EPP · EDR · XDR
사전 예방 탐지·대응 통합
┌───────────────┐ ┌──────────────┐ ┌──────────────────┐
│ EPP │ │ EDR │ │ XDR │
│ 백신·방화벽· │ → │ 엔드포인트 행위 │ → │ 엔드포인트+네트워크 │
│ 기기 제어 │ │ 기록·분석·격리 │ │ +이메일+클라우드 │
│ "들어오지 마" │ │ "들어왔으면 찾아 │ │ 상관 분석·자동 대응 │
│ │ │ 막는다" │ │ │
└───────────────┘ └──────────────┘ └──────────────────┘
| 구분 | EPP | EDR | XDR |
|---|---|---|---|
| 정식 명칭 | Endpoint Protection Platform | Endpoint Detection & Response | eXtended Detection & Response |
| 목적 | 예방(사전 차단) | 탐지·조사·대응(사후) | 여러 계층 통합 탐지·대응 |
| 핵심 기능 | 시그니처 백신, 개인 방화벽, 매체 제어, 앱 제어 | 단말 행위 지속 기록(텔레메트리), 위협 헌팅, 공격 흐름 시각화, 단말 격리, 프로세스 종료 | 엔드포인트·네트워크·이메일·클라우드·ID 데이터 상관 분석 |
| 강점 | 알려진 위협 | 알려지지 않은 위협, 파일리스, APT | 가시성 범위 최대 |
- MDR(Managed Detection & Response): EDR/XDR 운영을 외부 전문 업체가 대신해 주는 서비스.
- NDR: 네트워크 트래픽 기반 탐지·대응.
- 화이트리스트(애플리케이션 제어): 허용된 프로그램만 실행 → 알려지지 않은 악성코드에 강하지만 관리 부담.
3-8. 사회공학 공격
사회공학(Social Engineering): 기술이 아니라 사람의 심리(신뢰, 호기심, 두려움, 긴급성, 권위) 를 이용해 정보를 얻거나 행동을 유도하는 공격. 보안에서 가장 약한 고리는 사람이라는 점을 노린다.
유형 비교
| 공격 | 매체·대상 | 핵심 특징 |
|---|---|---|
| 피싱(Phishing) | 이메일·웹, 불특정 다수 | 가짜 메일 + 가짜 사이트로 계정·금융정보 입력 유도 |
| 스피어 피싱 | 이메일, 특정 개인·조직 | 대상 맞춤 내용(이름, 직책, 업무) → APT 최초 침투의 단골 |
| 웨일링(Whaling) | 경영진·고위층(CEO, CFO) | 고래(큰 물고기) 사냥. 송금 승인 권한 노림 |
| BEC(비즈니스 이메일 침해) | 기업 거래 이메일 | 거래처·임원 사칭해 대금 계좌 변경 요청 |
| 파밍(Pharming) | DNS·hosts 파일 변조 | 사용자가 정상 주소를 직접 입력해도 가짜 사이트로 연결 |
| 스미싱(Smishing) | SMS(문자) | 택배·청첩장·결제 문자 + 악성 앱 설치 링크 |
| 큐싱(Qshing) | QR 코드 | QR 위에 가짜 QR을 붙이거나 메일에 QR 첨부 |
| 비싱(Vishing) | 음성 전화(Voice) | 보이스피싱. 수사기관·금융기관 사칭 |
| 워터링 홀(Watering Hole) | 타깃이 자주 방문하는 웹사이트 | 그 사이트를 먼저 감염시켜 놓고 기다림(물웅덩이에서 사냥감을 기다리는 맹수) |
| 프리텍스팅 | 전화·대면 | 그럴듯한 상황(핑계)을 만들어 정보 요구 |
| 베이팅(Baiting) | USB 등 미끼 | 주차장에 악성 USB 떨어뜨리기 |
| 테일게이팅·피기백킹 | 물리 출입 | 직원 뒤를 따라 출입문 통과 |
| 숄더 서핑 | 대면 | 어깨 너머로 비밀번호 엿보기 |
| 덤스터 다이빙 | 쓰레기통 | 버린 문서에서 정보 수집 |
파밍 동작 원리 (피싱과 구분 필수)
[피싱] 사용자 ──클릭──▶ 가짜 링크(bank-l0gin.com) ──▶ 가짜 사이트
└ 주소가 이상한 걸 눈치채면 피할 수 있음
[파밍] 사용자 ──입력: www.bank.com (정상 주소!)
│
▼ 변조된 hosts 파일 / DNS 캐시 / DNS 서버
"www.bank.com = 공격자 IP"
▼
가짜 사이트 ← 주소창은 정상처럼 보임
- 윈도우 hosts 파일:
C:\Windows\System32\drivers\etc\hosts, 리눅스:/etc/hosts. 이 파일 권한 점검(리눅스 600 이하)이 실기 단골인 이유.
3-9. APT (지능형 지속 위협)
APT(Advanced Persistent Threat)
- Advanced(지능적): 제로데이, 맞춤형 악성코드, 사회공학 조합.
- Persistent(지속적): 특정 목표를 위해 수개월~수년 잠복하며 은밀하게 활동.
- Threat(위협): 국가·조직 단위 공격자, 명확한 목표(기밀 탈취, 기반시설 파괴).
- 사례: 스턱스넷(2010, 이란 원심분리기 제어 시스템, USB로 망분리 우회), 국내 3·20 전산망 대란(2013), 한수원 정보 유출(2014).
APT 공격 단계 (일반적 생명주기)
flowchart LR
A["1 정찰
정보 수집"] --> B["2 최초 침투
스피어피싱·워터링홀
·제로데이"]
B --> C["3 거점 확보
백도어·C&C 연결"]
C --> D["4 권한 상승·
내부 확산
(Lateral Movement)"]
D --> E["5 정보 수집"]
E --> F["6 유출·파괴"]
F -.->|"지속 잠복"| C| 단계 | 하는 일 | 대응 |
|---|---|---|
| 정찰(Reconnaissance) | SNS·홈페이지에서 조직도, 이메일, 사용 SW 조사 | 공개 정보 최소화, 보안 인식 교육 |
| 최초 침투(Initial Compromise) | 스피어피싱 첨부파일, 워터링 홀, 제로데이 | 메일 보안, 샌드박스, 패치 |
| 거점 확보(Establish Foothold) | 백도어·RAT 설치, C&C 통신 | EDR, 아웃바운드 트래픽 감시 |
| 권한 상승·내부 이동 | 자격증명 탈취(Pass-the-Hash), 다른 서버로 확산 | 계정 최소 권한, 망 분리, 다중 인증 |
| 정보 수집·유출(Exfiltration) | 압축·암호화 후 외부 전송 | DLP, 이상 트래픽 탐지 |
사이버 킬 체인(Cyber Kill Chain, 록히드 마틴 7단계) — 단계 이름 순서가 출제된다.
- 정찰(Reconnaissance)
- 무기화(Weaponization) — 악성 문서·익스플로잇 제작
- 전달(Delivery) — 메일, 웹, USB
- 익스플로잇(Exploitation) — 취약점 공격으로 코드 실행
- 설치(Installation) — 악성코드·백도어 설치
- 명령 및 제어(C2)
- 목적 달성(Actions on Objectives)
핵심 사상: 어느 한 단계라도 끊으면 공격이 실패한다 → 단계별 방어(심층 방어).
참고: MITRE ATT&CK 는 실제 관측된 공격자의 전술(Tactics)·기법(Techniques) 을 매트릭스로 정리한 지식 베이스. 킬 체인보다 세분화되어 있다.
사회공학·APT 대응 (관리적 + 기술적)
- 관리적: 보안 인식 교육, 모의 훈련(모의 피싱 메일), 송금·계좌 변경 시 별도 채널(전화) 재확인 절차, 정보 공개 최소화.
- 기술적: 메일 필터링·SPF/DKIM/DMARC(발신 도메인 위조 방지), 첨부파일 샌드박스, URL 필터링, MFA, EDR, 망 분리, 최소 권한.
⚠️ 시험 함정 (Day 3)
- 트로이목마는 자기 복제를 하지 않는다. "트로이목마는 네트워크로 자기 복제한다"는 오답.
- 웜 = 독립 실행 + 네트워크 전파. "웜은 숙주 파일에 기생한다"는 오답(그건 바이러스).
- 파밍 vs 피싱: 정상 주소를 입력했는데 가짜 사이트 → 파밍(DNS·hosts 변조). 이상한 링크를 클릭 → 피싱.
- 스피어 피싱(특정 대상) vs 웨일링(고위층) vs 워터링 홀(자주 가는 사이트 감염).
- 비싱 = 음성(Voice), 스미싱 = SMS, 큐싱 = QR. 이름 섞어서 출제.
- 커널 모드 루트킷이 사용자 모드 루트킷보다 탐지가 어렵다. 반대로 내면 오답.
- 2세대 암호형은 몸체만 암호화하고 복호화 루틴은 고정 → 그 루틴으로 탐지 가능. 복호화 루틴까지 바꾸는 것이 다형성.
- 정적 분석은 실행하지 않는다. "정적 분석은 샌드박스에서 실행한다"는 오답.
- EPP = 예방, EDR = 탐지·대응(행위 기록, 격리). "EDR은 시그니처 기반 사전 차단만 한다"는 오답.
- 킬 체인 순서: 정찰 → 무기화 → 전달 → 익스플로잇 → 설치 → C2 → 목적 달성. 무기화와 전달 순서 바꾸기 주의.
기출 포인트 (Day 3)
- 악성코드 설명을 주고 이름(웜/트로이/루트킷/논리폭탄) 고르기 — 최다 빈출.
- 바이러스 세대별 특징, 특히 은폐형·다형성.
- 사회공학 공격 유형 설명 → 이름 매칭(파밍, 워터링 홀, 스피어 피싱 등).
- APT 특징과 단계, 사이버 킬 체인 순서.
- 정적·동적 분석의 차이와 도구.
- 실기에서는 "EDR의 기능", "랜섬웨어 대응 방안", "루트킷 탐지 방법"을 서술형으로.
확인 문제 (Day 3)
Q1. 다음 설명에 해당하는 악성코드는?
"정상적인 유틸리티 프로그램으로 위장해 사용자가 직접 설치하도록 유도하며, 설치 후 원격 제어 기능을 제공하지만 스스로 다른 파일이나 시스템으로 복제되지는 않는다."
① 웜 ② 파일 바이러스 ③ 트로이목마 ④ 매크로 바이러스
정답: ③
- ① 틀림: 웜은 네트워크로 스스로 복제·전파.
- ② 틀림: 바이러스는 숙주에 기생하며 자기 복제.
- ③ 맞음: 위장 + 비복제 = 트로이목마.
- ④ 틀림: 매크로 바이러스도 바이러스이므로 복제한다.
Q2. 감염될 때마다 암호화 방식과 복호화 루틴까지 변경해 고정된 시그니처로는 탐지하기 어려운 바이러스는?
① 원시형 바이러스 ② 암호형 바이러스 ③ 다형성 바이러스 ④ 부트 바이러스
정답: ③
- ① 틀림: 고정 코드, 쉽게 탐지.
- ② 틀림: 몸체만 암호화, 복호화 루틴은 고정이라 그 부분으로 탐지 가능.
- ③ 맞음.
- ④ 틀림: 감염 위치(부트 섹터) 기준 분류.
Q3. 사용자가 웹 브라우저에 정상적인 은행 주소를 직접 입력했음에도 공격자가 만든 가짜 사이트로 접속되었다. 이 공격의 원인으로 가장 가능성이 높은 것은?
① 스미싱 문자의 링크 클릭 ② hosts 파일 또는 DNS 정보 변조 ③ 워터링 홀 공격 ④ 숄더 서핑
정답: ②
- 정상 주소 입력 → 가짜 사이트 = 파밍. 이름 해석 단계(hosts, DNS)가 변조된 것.
- ① 틀림: 링크를 클릭하는 피싱 계열.
- ③ 틀림: 정상 사이트 자체가 감염되어 방문자에게 악성코드 유포.
- ④ 틀림: 어깨 너머로 엿보기.
Q4. 커널 모드 루트킷에 대한 설명으로 옳지 않은 것은?
① 시스템 콜 테이블을 후킹해 파일·프로세스를 숨길 수 있다 ② 적재 가능한 커널 모듈(LKM) 형태로 삽입될 수 있다 ③ ls, ps 등 사용자 명령어 바이너리의 해시만 비교하면 항상 탐지할 수 있다 ④ 사용자 모드 루트킷보다 일반적으로 탐지가 어렵다
정답: ③
- ③ 틀림: 커널 루트킷은 바이너리를 바꾸지 않고 커널 자체를 조작하므로 사용자 바이너리 해시가 정상으로 나온다. 바이너리 해시 비교로 잘 잡히는 것은 사용자 모드 루트킷.
- ①②④ 맞음.
Q5. 록히드 마틴의 사이버 킬 체인 단계를 순서대로 바르게 나열한 것은?
① 정찰 → 전달 → 무기화 → 익스플로잇 → 설치 → C2 → 목적 달성
② 정찰 → 무기화 → 전달 → 익스플로잇 → 설치 → C2 → 목적 달성
③ 무기화 → 정찰 → 전달 → 설치 → 익스플로잇 → C2 → 목적 달성
④ 정찰 → 무기화 → 익스플로잇 → 전달 → C2 → 설치 → 목적 달성
정답: ②
- 정보를 모으고(정찰) → 무기를 만들고(무기화) → 보내고(전달) → 취약점을 터뜨리고(익스플로잇) → 심고(설치) → 원격 조종(C2) → 목적 달성.
Q6. EDR(Endpoint Detection and Response)의 기능으로 가장 거리가 먼 것은?
① 엔드포인트 행위 데이터의 지속적 수집·기록 ② 의심 단말의 네트워크 격리 ③ 공격 흐름 시각화 및 위협 헌팅 지원 ④ 네트워크 경계에서 패킷을 검사해 침입을 차단하는 인라인 방화벽 기능
정답: ④
- ④ 틀림: 네트워크 경계 인라인 차단은 방화벽·IPS의 역할. EDR은 단말(엔드포인트) 에 에이전트를 설치해 행위를 기록·분석·대응한다.
- ①②③ 맞음.
Day 4 · 리눅스 보안 점검 · Nmap (실기와 직결)
기본 개념(권한 비트, SUID/SGID/Sticky,
/etc/passwd·/etc/shadow필드, 로그 파일 종류, syslog 설정)은 Week02_운영체제 기초 에 있다. 여기서는 "점검 명령 → 결과 → 양호/취약 판단 → 조치" 흐름으로 익힌다.
4-1. 취약점 점검의 틀
주요정보통신기반시설 기술적 취약점 분석·평가 가이드(KISA 발간, 실무에서 "U-01" 같은 항목 번호로 부름)는 유닉스/리눅스 서버 점검 항목을 크게 5개 영역으로 나눈다. 판정은 항목마다 양호 / 취약 으로 낸다.
| 영역 | 대표 점검 항목 |
|---|---|
| 1. 계정 관리 | root 원격 접속 제한(U-01), 패스워드 복잡성, 계정 잠금 임계값, 패스워드 파일 보호(shadow), UID 0 계정, su 제한, 불필요 계정 |
| 2. 파일 및 디렉터리 관리 | PATH 설정, 소유자 없는 파일, 주요 파일 권한(passwd·shadow·hosts·inetd.conf·syslog.conf·services), SUID/SGID, World Writable, .rhosts·hosts.equiv, 접속 IP 제한, umask, 홈 디렉터리 |
| 3. 서비스 관리 | finger, Anonymous FTP, r 계열, cron 권한, DoS 취약 서비스(echo·chargen 등), NFS, automountd, RPC, NIS, tftp·talk, Sendmail, DNS, 웹 서버(Apache) 설정, SSH 사용, ftp 계정 쉘, SNMP 커뮤니티 |
| 4. 패치 관리 | 최신 보안 패치 적용 |
| 5. 로그 관리 | 로그 정기 검토, 정책에 따른 로깅 설정 |
항목 번호는 가이드 개정판마다 바뀔 수 있으니 번호보다 "항목 이름 + 판단 기준" 으로 외운다. 단 U-01 = root 원격 접속 제한 은 너무 유명해서 그대로 기억해 두자.
4-2. 계정 관리
① root 원격 접속 제한
왜? root로 바로 원격 로그인되면 (1) 무차별 대입 공격의 표적이 root 하나로 집중되고 (2) 누가 root를 썼는지 책임 추적이 안 된다. 정답은 "일반 계정으로 로그인 → su/sudo".
# SSH
$ grep -i "^PermitRootLogin" /etc/ssh/sshd_config
PermitRootLogin yes ← 취약
PermitRootLogin no ← 양호
# 조치: no 로 수정 후 재시작
$ sudo systemctl restart sshd
최신 OpenSSH의 기본값은
prohibit-password(키 인증만 허용)이지만, 점검 가이드 기준은no가 양호.
# Telnet (사용 시)
$ cat /etc/securetty | grep pts
pts/0 ← 취약 (pts = 원격 가상 터미널)
pts/1
# 조치: pts/* 줄을 모두 삭제·주석 처리
$ grep pam_securetty /etc/pam.d/login
auth required pam_securetty.so ← 이 줄이 있어야 securetty 가 적용됨
tty(콘솔)는 남기고pts(원격) 만 제거한다.- 더 좋은 조치: Telnet 자체를 끄고 SSH 사용(평문 전송 문제).
② 패스워드 복잡성·사용 기간
$ grep -E "^PASS_(MAX|MIN)_(DAYS|LEN)" /etc/login.defs
PASS_MAX_DAYS 90 ← 최대 사용 기간 (90일 이하 권장)
PASS_MIN_DAYS 1 ← 최소 사용 기간 (바로 원래 암호로 되돌리기 방지)
PASS_MIN_LEN 8
$ cat /etc/security/pwquality.conf | grep -v "^#"
minlen = 8
dcredit = -1 ← 숫자 최소 1자 (음수 = "최소 개수")
ucredit = -1 ← 대문자
lcredit = -1 ← 소문자
ocredit = -1 ← 특수문자
- 판단: 영문·숫자·특수문자 조합 8자 이상(조합 수에 따라 10자 이상) 등 가이드 기준 충족 시 양호.
chage -l 사용자로 개별 계정의 만료 정보 확인.
③ 계정 잠금 임계값
# RHEL 8/9 계열: pam_faillock
$ grep faillock /etc/pam.d/system-auth
auth required pam_faillock.so preauth silent deny=5 unlock_time=600
auth [default=die] pam_faillock.so authfail deny=5 unlock_time=600
# 또는 /etc/security/faillock.conf 에 deny = 5
# 구버전: pam_tally2
auth required pam_tally2.so deny=5 unlock_time=120 no_magic_root
account required pam_tally2.so no_magic_root reset
- 판단: 실패 임계값 10회 이하(가이드 기준) 설정 시 양호, 설정 없으면 취약. 실무 권장 5회.
- 잠긴 계정 확인/해제:
faillock --user kim,faillock --user kim --reset(구버전pam_tally2 -u kim -r).
④ 패스워드 파일 보호 (shadow 사용)
$ head -2 /etc/passwd
root:x:0:0:root:/root:/bin/bash ← 두 번째 필드 'x' = shadow 사용 → 양호
kim:$6$Ab..:1000:1000::/home/kim:/bin/bash ← 해시가 passwd 에 있음 → 취약
# 조치: pwconv (passwd → shadow 로 분리)
⑤ UID 0 계정 (root 이외)
$ awk -F: '$3==0 {print $1}' /etc/passwd
root
toor ← 취약: root 외 UID 0 은 백도어 의심
# 조치: usermod -u 로 UID 변경 또는 계정 삭제
⑥ su 명령 사용 제한
$ grep pam_wheel /etc/pam.d/su
auth required pam_wheel.so use_uid ← 주석(#) 없으면 양호
$ ls -l /usr/bin/su
-rwsr-x---. 1 root wheel ... /usr/bin/su ← 그룹 wheel, 4750 → 양호
-rwsr-xr-x. 1 root root ... /usr/bin/su ← 누구나 su 실행 가능 → 취약
- 조치: wheel 그룹 생성·관리자만 추가(
usermod -aG wheel admin),chgrp wheel /usr/bin/su; chmod 4750 /usr/bin/su.
⑦ 불필요한 계정·로그인 쉘
$ grep -E "^(lp|uucp|nuucp|games|news):" /etc/passwd
games:x:12:100:games:/usr/games:/bin/bash ← 취약: 로그인 불필요 계정에 쉘
# 조치
$ usermod -s /sbin/nologin games # 또는 /bin/false
$ userdel 불필요계정
4-3. 파일 및 디렉터리 관리
① PATH 환경변수
$ echo $PATH
.:/usr/local/bin:/usr/bin:/bin ← 취약: 맨 앞에 '.'
/usr/local/bin:/usr/bin:/bin: ← 취약: 끝의 ':' 도 현재 디렉터리
/usr/local/bin:/usr/bin:/bin ← 양호
왜 위험한가? 공격자가 /tmp 에 ls 라는 악성 스크립트를 만들어 두면, root가 /tmp 에서 ls 를 입력할 때 /bin/ls 대신 ./ls 가 root 권한으로 실행된다. . 이나 :: 가 PATH 앞·중간에 있으면 취약.
② 주요 파일 소유자·권한 기준 (가이드 판정 기준)
| 파일 | 소유자 | 권한 (이하) |
|---|---|---|
/etc/passwd |
root | 644 |
/etc/shadow |
root | 400 (000도 가능) |
/etc/hosts |
root | 600 |
/etc/(x)inetd.conf |
root | 600 |
/etc/(r)syslog.conf |
root(또는 bin, sys) | 640 |
/etc/services |
root(또는 bin, sys) | 644 |
hosts.lpd |
root | 600 |
$ ls -l /etc/shadow
----------. 1 root root 1234 ... /etc/shadow ← 000 양호
-rw-r--r--. 1 root root 1234 ... /etc/shadow ← 644 취약 (누구나 해시 읽기)
# 조치
$ chown root /etc/shadow; chmod 400 /etc/shadow
③ SUID/SGID 파일 점검
SUID 파일은 실행하는 동안 소유자(대개 root) 권한을 가진다. Day 2의 버퍼 오버플로가 있는 SUID root 파일 = 권한 상승 통로.
$ find / -user root -type f \( -perm -4000 -o -perm -2000 \) -xdev -exec ls -l {} \; 2>/dev/null
-rwsr-xr-x. 1 root root ... /usr/bin/passwd ← 정상(비밀번호 변경에 필요)
-rwsr-xr-x. 1 root root ... /usr/bin/sudo ← 정상
-rwsr-xr-x. 1 root root ... /usr/bin/newgrp
-rwsr-xr-x. 1 root root ... /tmp/.x/bash ← ★ 의심! /tmp 에 SUID 쉘
-rwxr-sr-x. 1 root lp ... /usr/bin/lpq
-perm -4000: SUID 비트가 포함된 파일,-perm -2000: SGID.- 판단: 불필요하거나 의심스러운 SUID/SGID 가 없으면 양호.
- 조치:
chmod u-s 파일,chmod g-s 파일. 반드시 필요한 것은 그룹 제한(chmod 4750). - 점검 팁: 기준 목록을 만들어 두고 주기적으로 diff — 새로 생긴 SUID는 침해 지표.
④ World Writable 파일
$ find / -type f -perm -2 -xdev -exec ls -l {} \; 2>/dev/null
-rw-rw-rw-. 1 root root 220 ... /etc/cron.daily/backup.sh ← ★ 취약
# 누구나 수정 가능한 root cron 스크립트 = 일반 사용자가 root 명령 실행 가능
# 조치
$ chmod o-w /etc/cron.daily/backup.sh
-perm -2: others 에 쓰기(w=2) 권한이 있는 것.- 디렉터리는
-type d -perm -2로 찾고,/tmp처럼 꼭 필요하면 Sticky Bit(chmod +t, 1777) 가 있는지 확인.
⑤ 소유자 없는 파일
$ find / \( -nouser -o -nogroup \) -xdev -ls 2>/dev/null
262 4 -rw-r--r-- 1 1005 1005 ... /home/olduser/.bashrc
- 삭제된 계정의 파일 → 새 계정이 같은 UID를 받으면 그 파일의 소유자가 됨. 조치: 삭제 또는 소유자 변경.
⑥ 사용자 홈·환경파일
- 홈 디렉터리 소유자 = 해당 계정, 타 사용자 쓰기 권한 없음.
.profile,.bashrc,.bash_profile,.rhosts등 환경 파일: 소유자 root 또는 해당 계정, 타 사용자 쓰기 금지.
⑦ umask
새로 만드는 파일의 기본 권한에서 뺄 값. 파일 기본 666, 디렉터리 777에서 umask를 뺀다(정확히는 비트 마스킹).
| umask | 새 파일 | 새 디렉터리 | 판정 |
|---|---|---|---|
| 000 | 666 (rw-rw-rw-) | 777 | 취약 |
| 002 | 664 | 775 | 취약(가이드 기준) |
| 022 | 644 (rw-r--r--) | 755 | 양호 |
| 027 | 640 | 750 | 양호 |
| 077 | 600 | 700 | 양호(가장 엄격) |
$ umask
0022 ← 양호
$ grep umask /etc/profile /etc/bashrc
/etc/profile: umask 022
4-4. 서비스 관리
① r 계열 서비스와 신뢰 관계(trust)
rlogin, rsh, rexec(TCP 513, 514, 512)는 신뢰 관계가 설정된 호스트·사용자라면 패스워드 없이 로그인시킨다. 편리하지만 IP/호스트명만 믿으므로 IP 스푸핑, 신뢰 파일 변조에 취약하고 평문 통신이다.
[호스트 A] ──"나 B의 kim이야"──▶ [호스트 B]
/etc/hosts.equiv 또는
~kim/.rhosts 에 A가 있으면
패스워드 없이 통과!
$ cat /etc/hosts.equiv
+ ← ★ 가장 위험: 모든 호스트 신뢰
$ cat /home/kim/.rhosts
+ + ← ★ 모든 호스트의 모든 사용자 신뢰
trusted-host kim ← 특정 호스트·사용자만 (그래도 권장 안 함)
$ ls -l /etc/hosts.equiv
-rw-------. 1 root root ... ← 소유자 root, 600 이하여야 함
- 판단: r 계열 서비스 미사용 → 양호. 사용 시
hosts.equiv,.rhosts의 소유자·권한(600 이하)·+미설정 확인. - 조치: 서비스 비활성화, 파일 삭제, SSH로 대체.
② 불필요 서비스 비활성화
| 서비스 | 위험 |
|---|---|
| finger (79) | 사용자 계정·로그인 정보 노출 |
| echo(7), discard(9), daytime(13), chargen(19) | DoS 공격(증폭·루프) 에 악용 |
| tftp (69/UDP) | 인증 없음 — 설정 파일 탈취 |
| talk, ntalk | 불필요 |
| telnet (23), ftp (21) | 평문 전송 → SSH/SFTP로 대체 |
| Anonymous FTP | 익명 접근, 파일 업로드 악용 |
| NFS, NIS, RPC 계열 | 공유 설정 오류 시 정보 노출 |
| SNMP | 기본 커뮤니티 public/private 사용 시 정보 노출·설정 변경 |
# systemd
$ systemctl list-unit-files --state=enabled | grep -E "telnet|rsh|rlogin|tftp|finger"
telnet.socket enabled ← 취약
$ systemctl disable --now telnet.socket
# xinetd 방식
$ cat /etc/xinetd.d/telnet
service telnet
{
disable = no ← 취약 (yes 로 변경)
...
}
# 구 inetd 방식: /etc/inetd.conf 에서 해당 줄 주석(#) 처리 후 inetd 재시작
③ xinetd 와 TCP Wrapper
- inetd/xinetd(슈퍼 데몬): 여러 서비스 포트를 대신 듣고 있다가 요청이 오면 해당 서비스 데몬을 띄워 준다. 상주 데몬 수를 줄임.
- TCP Wrapper(tcpd): 서비스 앞에서 접속 IP를 검사하는 경비원.
libwrap을 사용하는 서비스(sshd 구버전 등)나 inetd 계열에 적용.
flowchart TD
C["클라이언트 접속"] --> A{"/etc/hosts.allow
매칭?"}
A -->|"예"| OK["허용 (검사 종료)"]
A -->|"아니오"| D{"/etc/hosts.deny
매칭?"}
D -->|"예"| NO["거부"]
D -->|"아니오"| OK2["허용 (기본)"]# 권장 구성: 기본 거부 + 필요한 것만 허용
$ cat /etc/hosts.deny
ALL: ALL
$ cat /etc/hosts.allow
sshd: 192.168.10.0/255.255.255.0
sshd: 10.1.1.5
in.telnetd: 192.168.10.100
- 검사 순서 allow → deny, 먼저 매칭되면 끝. 둘 다 안 맞으면 허용.
- 그래서 deny에
ALL:ALL을 넣어 "명시적 허용 외 모두 거부(화이트리스트)" 구조를 만든다. - 판단: 접속 IP 제한이 설정되어 있으면 양호(TCP Wrapper, iptables/firewalld, 서비스 자체 설정 중 하나).
④ cron / at 접근 제어
cron.allow 존재? ── 예 ──▶ 목록에 있는 사용자만 사용 가능 (deny 무시)
│
아니오
▼
cron.deny 존재? ── 예 ──▶ 목록에 있는 사용자만 사용 불가
│
아니오
▼
배포판에 따라 root만 또는 모두 사용 가능
$ ls -l /etc/cron.allow /etc/cron.deny
-rw-r-----. 1 root root 6 ... /etc/cron.allow ← 소유자 root, 640 이하 양호
$ cat /etc/cron.allow
root
admin
- 판단: cron 관련 파일 소유자 root, 권한 640 이하면 양호.
at.allow/at.deny도 같은 원리. - crontab에 등록된 스크립트 자체가 World Writable 인지도 함께 본다(4-3 ④).
⑤ SSH 추가 하드닝 (실무 권장)
# /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no # 키 인증만
PermitEmptyPasswords no
MaxAuthTries 3
Protocol 2 # (구버전) SSHv1 금지
AllowUsers admin kim
ClientAliveInterval 300 # 유휴 세션 정리
Banner /etc/issue.net # 경고 배너
4-5. 패치 · 로그 관리
패치 관리
- 정기적으로 보안 패치 적용:
dnf update --security(RHEL),apt update && apt upgrade(Debian/Ubuntu). - 운영 서버는 테스트 서버에서 먼저 검증 후 적용, 패치 이력 관리.
- 커널 패치는 재부팅 필요(또는 라이브 패치).
로그 관리
- 주요 로그 위치·의미는 Week02_운영체제 기초 참고 (
wtmp/btmp/utmp/lastlog,secure·auth.log,messages). - 점검 포인트
rsyslog.conf에 인증·커널·긴급 로그 기록 설정이 있는가- 로그 파일 권한(타인 쓰기 금지), 정기 검토 절차가 있는가
- logrotate: 로그 순환·압축·보관 기간 관리 (
/etc/logrotate.conf) - 원격 로그 서버로 전송: 공격자가 로컬 로그를 지워도 사본이 남음 (
*.* @@logserver:514—@@TCP,@UDP)
- 리눅스 감사: auditd (
auditctl -w /etc/passwd -p wa -k passwd_change→ 파일 쓰기·속성 변경 감시)
$ lastb | head -3 # 로그인 실패 (btmp)
root ssh:notty 203.0.113.7 Sun Dec 28 03:12 - 03:12 (00:00)
root ssh:notty 203.0.113.7 Sun Dec 28 03:12 - 03:12 (00:00)
admin ssh:notty 203.0.113.7 Sun Dec 28 03:11 - 03:11 (00:00)
# → 같은 IP에서 짧은 간격 반복 실패 = 무차별 대입 시도. 차단·계정잠금 확인
4-6. 무결성 점검: Tripwire · AIDE
루트킷·백도어는 시스템 파일을 바꾼다. "원래 상태의 지문(해시)"을 저장해 두고 주기적으로 비교하면 변조를 찾을 수 있다. 이것이 호스트 기반 무결성 점검(FIM, File Integrity Monitoring).
Tripwire 작업 흐름
flowchart TD
A["1 정책 파일 작성
감시할 파일·속성 지정
twpol.txt"] --> B["2 키 생성·정책 서명
site key / local key"]
B --> C["3 기준 DB 생성
tripwire --init
(깨끗한 상태에서!)"]
C --> D["4 주기적 점검
tripwire --check
cron 으로 자동화"]
D --> E{"변경 발견?"}
E -->|"정상 변경
(패치 등)"| F["5 DB 갱신
tripwire --update"]
E -->|"비인가 변경"| G["침해 대응"]
F --> D$ tripwire --check
Open Source Tripwire(R) Integrity Check Report
...
Rule Name Severity Level Added Removed Modified
--------- -------------- ----- ------- --------
* Critical system boot files 100 0 0 0
* System binaries 100 1 0 2
...
Modified:
"/usr/bin/ps"
"/usr/bin/netstat"
Added:
"/usr/bin/.sshd2"
→ ps, netstat 변경 + 숨김 파일 추가 = 사용자 모드 루트킷 강력 의심.
- 원리: 파일의 해시(MD5, SHA 등), 크기, 권한, 소유자, inode, 수정 시각을 DB에 기록해 비교.
- 기준 DB는 반드시 설치 직후·클린 상태에서 생성하고, DB·정책 파일은 암호화·서명, 가능하면 읽기 전용 매체에 보관(공격자가 DB까지 고치면 무용지물).
- AIDE(Advanced Intrusion Detection Environment): Tripwire와 같은 원리의 오픈소스.
aide --init→aide.db.new.gz를aide.db.gz로 이름 변경 →aide --check. - 간이 방법:
rpm -Va(RPM 패키지 파일 검증),sha256sum비교,debsums.
4-7. Nmap — 네트워크 스캐닝 도구
왜 시스템 보안에 스캐너가? 공격자는 공격 전 "어떤 서버가 살아 있고, 어떤 포트·서비스·버전이 열려 있는지" 먼저 조사(정찰)한다. 관리자도 같은 도구로 불필요하게 열린 포트를 먼저 찾아 닫는다.
주요 스캔 유형
| 옵션 | 이름 | 방식 | 열림 | 닫힘 |
|---|---|---|---|---|
-sT |
TCP Connect | 3-way handshake 완전 연결 | SYN/ACK → 연결 | RST |
-sS |
SYN(Half-open, Stealth) | SYN만 보내고 SYN/ACK 받으면 RST로 끊음 → 로그 덜 남음, root 필요 | SYN/ACK | RST |
-sF |
FIN | FIN 플래그만 | 응답 없음 | RST |
-sX |
Xmas | FIN+PSH+URG | 응답 없음 | RST |
-sN |
NULL | 플래그 없음 | 응답 없음 | RST |
-sA |
ACK | ACK만 → 방화벽 필터링 여부 판단 | — | RST 오면 unfiltered |
-sU |
UDP | UDP 패킷 | 응답 또는 없음 | ICMP Port Unreachable |
FIN/Xmas/NULL 스캔은 RFC 793 동작에 의존 — 윈도우는 열린 포트에도 RST 를 보내 구분이 안 된다(리눅스·유닉스 대상에서 유효).
주요 옵션
| 옵션 | 기능 |
|---|---|
-sn |
호스트 발견만(핑 스캔, 포트 스캔 X) — 구버전 -sP |
-Pn |
호스트 발견 생략(ICMP 막힌 대상) |
-p 22,80 / -p- |
포트 지정 / 전체 65535 |
-sV |
서비스 버전 탐지 |
-O |
OS 탐지(TCP/IP 핑거프린팅) |
-A |
공격적 스캔: -O -sV -sC --traceroute |
-sC, --script |
NSE(Nmap Scripting Engine) 스크립트 실행, 예: --script vuln |
-T0~-T5 |
타이밍(0 Paranoid 느림·은밀 ~ 5 Insane 빠름) |
-D |
디코이(미끼 IP 섞기) |
-oN / -oX / -oG / -oA |
일반 / XML / grep용 / 모두 저장 |
포트 상태 6가지: open, closed, filtered(방화벽이 막아 판단 불가), unfiltered(ACK 스캔: 도달은 하나 열림 여부 모름), open|filtered, closed|filtered.
예시 (자신이 관리하는 서버 점검)
$ sudo nmap -sS -sV -O -p 1-1024 192.168.10.20
Starting Nmap 7.94 ( https://nmap.org )
Nmap scan report for 192.168.10.20
Host is up (0.00041s latency).
Not shown: 1017 closed tcp ports (reset)
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
22/tcp open ssh OpenSSH 8.0 (protocol 2.0)
23/tcp open telnet Linux telnetd
80/tcp open http Apache httpd 2.4.37
111/tcp open rpcbind 2-4 (RPC #100000)
512/tcp open exec netkit-rsh rexecd
513/tcp open login
OS details: Linux 4.15 - 5.8
Nmap done: 1 IP address (1 host up) scanned in 9.12 seconds
결과 판단 (관리자 관점)
- 23/telnet → 평문 원격 접속 → 취약, SSH로 대체 후 비활성.
- 512/513 (rexec, rlogin) → r 계열 → 취약, 비활성.
- 21/ftp → 평문, Anonymous 허용 여부 확인, SFTP 권장.
- 111/rpcbind → 불필요하면 비활성.
- 서비스 버전 노출(Apache 2.4.37) → 배너 숨김(
ServerTokens Prod), 최신 패치 확인.
⚠️ 허가받지 않은 대상 스캔은 정보통신망법 위반 소지가 있다. 실습은 자신의 랩 환경에서만.
⚠️ 시험 함정 (Day 4)
- TCP Wrapper는 hosts.allow 먼저, 매칭되면 즉시 종료. 둘 다 매칭 안 되면 허용(거부 아님).
cron.allow가 있으면 cron.deny는 무시된다./etc/shadow권한 기준은 400 이하,/etc/passwd는 644 이하,/etc/hosts는 600 이하. 숫자 섞기 주의.- PATH에서
.이 맨 뒤에 있는 것은 상대적으로 덜 위험하지만, 가이드는 앞이나 중간의.·::를 취약으로 본다. find -perm -4000은 SUID,-2000은 SGID,-1000은 Sticky,-perm -2는 others 쓰기. 숫자 위치 혼동 금지.- Telnet root 제한은
/etc/securetty의 pts 제거, SSH는PermitRootLogin no. 서로 바꿔 낸 보기 주의. .rhosts/hosts.equiv의+는 "모두 신뢰"라 가장 위험.- umask 022 → 파일 644, 디렉터리 755. "파일 755"는 오답(파일 기본은 666에서 뺌).
- SYN 스캔은 연결을 완성하지 않는다(Half-open). 완전 연결은
-sT. - Xmas = FIN+PSH+URG. "SYN+ACK+FIN"은 오답. 닫힌 포트는 RST, 열린 포트는 무응답.
- Tripwire 기준 DB는 침해 후가 아니라 클린 상태에서 만들어야 의미가 있다.
기출 포인트 (Day 4)
- 점검 명령어와 목적 매칭(
find -perm -4000,find -nouser,awk -F: '$3==0'). - TCP Wrapper 동작 순서, 설정 예시 해석.
- r 계열 서비스의 신뢰 관계 파일 이름과 위험성.
- umask 계산 문제.
- 실기: 설정 파일 일부를 보여 주고 취약한 이유 + 조치 방법 서술 (PermitRootLogin, pam_faillock, su 제한 등).
- Nmap 스캔 옵션별 특징, 스텔스 스캔의 원리, 열린/닫힌 포트의 응답 차이.
- Tripwire의 원리(해시 기반 무결성)와 사용 순서.
확인 문제 (Day 4)
Q1. 다음 TCP Wrapper 설정에서 IP 192.168.10.50 이 sshd 에 접속을 시도할 때의 결과는?
/etc/hosts.allow : sshd: 192.168.10.0/255.255.255.0
/etc/hosts.deny : ALL: ALL
① hosts.deny 의 ALL:ALL 이 우선이라 거부된다 ② hosts.allow 에 먼저 매칭되어 허용된다 ③ 두 파일 모두 매칭되므로 기본 정책에 따라 거부된다 ④ TCP Wrapper는 sshd 에 적용되지 않으므로 항상 허용된다
정답: ②
- 검사 순서는 allow → deny, 먼저 매칭되면 그 결과로 끝난다. 192.168.10.50은 allow의 네트워크에 포함되므로 허용.
- ① 틀림: deny는 allow에 매칭되지 않았을 때만 본다.
- ③ 틀림: "둘 다 매칭" 개념이 없다. 첫 매칭에서 종료.
- ④ 틀림: libwrap을 지원하는 빌드라면 적용된다(본 문제는 동작 원리를 묻는 것).
Q2. 리눅스 서버 점검 결과 umask 값이 027로 설정되어 있다. 새로 생성되는 일반 파일의 권한은?
① 750 ② 640 ③ 644 ④ 600
정답: ②
- 파일 기본 666에서 027을 마스킹: 소유자 6(rw), 그룹 6-2=4(r), 기타 6-7→0. → 640.
- ① 750은 디렉터리의 결과(777-027).
Q3. 다음 중 root 권한으로 SUID가 설정된 파일을 찾는 명령으로 옳은 것은?
① find / -user root -perm -4000 ② find / -user root -perm -1000 ③ find / -perm -2 -type f ④ find / -nouser
정답: ①
- ② 틀림: 1000은 Sticky Bit.
- ③ 틀림: World Writable 파일.
- ④ 틀림: 소유자 없는 파일.
Q4. r 계열 서비스와 관련된 설명으로 옳지 않은 것은?
① rlogin, rsh, rexec 가 해당한다 ② /etc/hosts.equiv 와 $HOME/.rhosts 로 신뢰 관계를 설정한다 ③ 신뢰 파일에 '+' 를 설정하면 신뢰 대상을 엄격히 제한하는 의미가 된다 ④ 통신이 암호화되지 않아 SSH로 대체하는 것이 바람직하다
정답: ③
- ③ 틀림:
+는 모든 호스트(또는 사용자)를 신뢰한다는 뜻으로 가장 위험하다. - ①②④ 맞음.
Q5. Nmap 스캔 중 FIN, PSH, URG 플래그를 설정해 전송하며, 대상 포트가 닫혀 있으면 RST 응답을, 열려 있으면 응답이 없는 것을 이용하는 스캔은?
① SYN 스캔 ② ACK 스캔 ③ Xmas 스캔 ④ Connect 스캔
정답: ③
- ① 틀림: SYN만 전송, 열림 시 SYN/ACK.
- ② 틀림: ACK만 전송, 방화벽 필터 여부 확인용.
- ③ 맞음: 플래그가 크리스마스 트리처럼 켜진다고 Xmas.
- ④ 틀림: 완전한 3-way handshake.
Q6. Tripwire 운영에 대한 설명으로 가장 적절하지 않은 것은?
① 파일의 해시값과 속성 정보를 기준 데이터베이스에 저장한다 ② 기준 데이터베이스는 침해 사고가 의심될 때 처음 생성한다 ③ 정상적인 패치 후에는 데이터베이스를 갱신한다 ④ 데이터베이스와 정책 파일은 변조되지 않도록 보호해야 한다
정답: ②
- ② 틀림: 침해 후 만든 DB는 이미 변조된 상태를 "정상"으로 기록한다. 설치 직후 클린 상태에서 생성해야 한다.
- ①③④ 맞음.
Day 5 · 윈도우 보안 심화 · 계정 공격
SAM, SID(RID 500 = Administrator, 501 = Guest), 레지스트리 하이브 구조, 이벤트 로그 기본은 Week02_운영체제 기초 참고. 여기서는 점검·설정 위치·공격 원리에 집중한다.
5-1. 윈도우 보안 설정 도구 지도
| 도구 | 실행 | 용도 |
|---|---|---|
| 로컬 보안 정책 | secpol.msc |
계정 정책(암호·잠금), 로컬 정책(감사·사용자 권한·보안 옵션) |
| 로컬 그룹 정책 편집기 | gpedit.msc |
secpol 포함 더 넓은 정책 |
| 그룹 정책 관리(도메인) | gpmc.msc |
AD 도메인 전체에 GPO 배포 |
| 컴퓨터 관리 | compmgmt.msc |
사용자·그룹, 공유 폴더, 이벤트 뷰어, 서비스 |
| 서비스 | services.msc |
서비스 시작 유형(자동/수동/사용 안 함) |
| 이벤트 뷰어 | eventvwr.msc |
보안·시스템·응용 프로그램 로그 |
| 레지스트리 편집기 | regedit |
세부 설정 값 |
| 명령줄 | net, reg, wevtutil, auditpol, PowerShell |
점검 자동화 |
5-2. 계정 관리
① Administrator 계정 이름 변경
- 기본 이름
Administrator는 누구나 알기 때문에 무차별 대입의 표적. 이름을 바꾸고, 같은 이름의 권한 없는 미끼 계정을 두기도 한다. - 단, SID의 RID 500은 이름을 바꿔도 그대로 → 이름 변경만으로 완벽하지 않다(SID 조회로 찾을 수 있음). 그래서 익명 SID/이름 변환 차단과 함께 쓴다.
- 경로: secpol → 로컬 정책 → 보안 옵션 → "계정: Administrator 계정 이름 바꾸기".
② Guest 계정 비활성화
C:\> net user guest
사용자 이름 guest
...
활성 계정 아니요 ← 양호
예 ← 취약
C:\> net user guest /active:no
③ 관리자 그룹 최소화
C:\> net localgroup administrators
별칭 administrators
구성원
-------------------------------------------------------
Administrator
kim
backup_svc ← 불필요한 관리자 권한? 확인 필요
④ 암호 정책 / 계정 잠금 정책 (secpol → 계정 정책)
| 정책 | 권장 기준(가이드 예시) |
|---|---|
| 암호는 복잡성을 만족해야 함 | 사용 |
| 최소 암호 길이 | 8자 이상 |
| 최대 암호 사용 기간 | 90일 이하 |
| 최소 암호 사용 기간 | 1일 이상 |
| 최근 암호 기억 | 4개 이상 |
| 해독 가능한 암호화를 사용하여 암호 저장 | 사용 안 함 (사실상 평문 저장) |
| 계정 잠금 임계값 | 5회 이하 |
| 계정 잠금 기간 / 잠금 수 초기화 시간 | 60분 이상 |
C:\> net accounts
강제 로그오프 시간: 사용 안 함
최소 암호 사용 기간(일): 1
최대 암호 사용 기간(일): 90
최소 암호 길이: 8
암호 기록 개수: 4
잠금 임계값: 5
잠금 기간(분): 60
잠금 관찰 창(분): 60
⑤ LM 해시 저장 안 함
- LM 해시: 암호를 대문자로 바꾸고 7자씩 두 조각으로 나눠 DES로 처리 → 14자 암호도 사실상 7자 두 개를 따로 크랙. 솔트도 없음. 매우 약하다.
- NTLM 해시(NT 해시): 암호의 유니코드 MD4 해시. LM보다 강하지만 솔트가 없어 레인보우 테이블·Pass-the-Hash에 취약.
- 설정: secpol → 보안 옵션 → "네트워크 보안: 다음 암호 변경 시 LAN Manager 해시 값 저장 안 함" = 사용 (레지스트리
HKLM\SYSTEM\CurrentControlSet\Control\Lsa\NoLMHash = 1). - "네트워크 보안: LAN Manager 인증 수준" = NTLMv2 응답만 보냄, LM 및 NTLM 거부 (
LmCompatibilityLevel = 5).
⑥ 기타 보안 옵션
- "대화형 로그온: 마지막 사용자 이름 표시 안 함" = 사용 (계정명 노출 방지)
- "대화형 로그온: Ctrl+Alt+Del을 사용할 필요 없음" = 사용 안 함 (신뢰 경로 SAS 유지, Day 1)
- "네트워크 액세스: 익명 SID/이름 변환 허용" = 사용 안 함
- "시스템 종료: 로그온하지 않고 시스템 종료 허용" = 사용 안 함
- 화면 보호기 암호·대기 시간 설정, 원격 데스크톱 접근 그룹 제한
5-3. 공유 관리 · 널 세션
기본(관리) 공유: 윈도우는 관리 목적으로 숨김 공유(이름 끝 $)를 자동 생성한다.
C:\> net share
공유 이름 리소스 설명
------------------------------------------------------------------
C$ C:\ 기본 공유
IPC$ 원격 IPC
ADMIN$ C:\Windows 원격 관리
Data D:\Data (사용자 공유)
명령을 잘 실행했습니다.
| 공유 | 용도 | 위험 |
|---|---|---|
C$, D$ |
드라이브 전체 | 관리자 자격증명이 털리면 전체 파일 접근, 악성코드 원격 복사 |
ADMIN$ |
C:\Windows |
원격 실행 도구가 서비스 바이너리 복사에 사용(내부 확산) |
IPC$ |
프로세스 간 통신(명명된 파이프) | 널 세션 의 통로 |
기본 공유 제거
- 일시:
net share C$ /delete→ 재부팅하면 다시 생성됨. - 영구: 레지스트리
- 경로
HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters - 서버 OS:
AutoShareServer= 0 (REG_DWORD) - 클라이언트 OS:
AutoShareWks= 0
- 경로
C:\> reg query HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters /v AutoShareServer
AutoShareServer REG_DWORD 0x0 ← 양호
(값이 없거나 0x1) ← 취약 (기본 공유 자동 생성)
일반 공유 폴더 점검
- 공유 권한에 Everyone 이 있으면 취약 → 필요한 사용자·그룹만.
- 불필요한 공유는 제거.
널 세션(Null Session)
- 사용자 이름·암호 없이(빈 값으로)
IPC$에 연결하는 것:net use \\대상\IPC$ "" /u:"" - 과거에는 이 익명 연결로 사용자 계정 목록, 공유 목록, 정책 정보를 열거할 수 있었다 → 공격 정찰에 악용.
- 제한:
HKLM\SYSTEM\CurrentControlSet\Control\Lsa\RestrictAnonymous
| 값 | 의미 |
|---|---|
| 0 | 제한 없음 (기본, 취약) |
| 1 | 익명 사용자의 SAM 계정·공유 열거 차단 |
| 2 | 명시적 익명 권한이 없으면 접근 불가 (Windows 2000 에서만 의미, 이후 버전에서는 부작용 우려) |
- 관련 값:
RestrictAnonymousSAM = 1,EveryoneIncludesAnonymous = 0 - 대응하는 secpol 항목: "네트워크 액세스: SAM 계정과 공유의 익명 열거 허용 안 함" = 사용.
5-4. 서비스 관리
| 비활성 권장 서비스(불필요 시) | 이유 |
|---|---|
| Telnet | 평문 |
| FTP(IIS) / Anonymous FTP | 평문, 익명 접근 |
| SNMP (기본 커뮤니티) | public 커뮤니티로 정보 노출 |
| 원격 레지스트리(Remote Registry) | 원격에서 레지스트리 조회·수정 |
| NetBIOS over TCP/IP | 137~139 포트 정보 노출 → 필요 없으면 해제 |
| 불필요한 IIS 기능 | 디렉터리 리스팅, 샘플 파일, WebDAV |
| 터미널 서비스(RDP) | 사용 시 NLA, 접속 IP 제한, 기본 포트 변경, 세션 타임아웃 |
C:\> sc query RemoteRegistry
SERVICE_NAME: RemoteRegistry
STATE : 4 RUNNING ← 불필요하면 취약
C:\> sc config RemoteRegistry start= disabled
C:\> sc stop RemoteRegistry
열린 포트·프로세스 확인
C:\> netstat -ano | findstr LISTENING
TCP 0.0.0.0:135 0.0.0.0:0 LISTENING 912
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4
TCP 0.0.0.0:3389 0.0.0.0:0 LISTENING 1180
TCP 0.0.0.0:4444 0.0.0.0:0 LISTENING 6620 ← ★ 의심
C:\> tasklist /FI "PID eq 6620"
이미지 이름 PID 세션 이름 ...
svch0st.exe 6620 Console ← 이름 위장(svchost 흉내)
- 445(SMB)는 외부 노출 금지(웜 전파 경로). 4444 같은 낯선 포트 + 위장 프로세스명 = 백도어 의심.
5-5. 감사 정책과 이벤트 로그
감사 정책 (secpol → 로컬 정책 → 감사 정책)
| 항목 | 권장 | 무엇을 남기나 |
|---|---|---|
| 계정 로그온 이벤트 감사 | 성공·실패 | 도메인 컨트롤러가 자격증명 검증 |
| 로그온 이벤트 감사 | 성공·실패 | 해당 컴퓨터 로그온·로그오프 |
| 계정 관리 감사 | 성공·실패 | 계정 생성·삭제·변경·암호 재설정 |
| 정책 변경 감사 | 성공(·실패) | 감사·권한 정책 변경 |
| 권한 사용 감사 | 실패 | 특권 사용 |
| 디렉터리 서비스 액세스 감사 | 실패 | AD 객체 접근 |
| 개체 액세스 감사 | 실패 | 파일·레지스트리 접근(SACL 설정 필요) |
| 시스템 이벤트 감사 | 성공·실패 | 시스템 시작·종료, 보안 로그 영향 |
| 프로세스 추적 감사 | 필요 시 | 프로세스 생성(4688) |
C:\> auditpol /get /category:"로그온/로그오프"
시스템 감사 정책
범주/하위 범주 설정
로그온/로그오프
로그온 성공 및 실패 ← 양호
로그오프 성공
계정 잠금 성공
주요 보안 이벤트 ID (Week02 기본에 추가)
| ID | 의미 | 분석 포인트 |
|---|---|---|
| 4624 | 로그온 성공 | 로그온 유형 확인 |
| 4625 | 로그온 실패 | 같은 IP 반복 → 무차별 대입 |
| 4634 / 4647 | 로그오프 / 사용자 시작 로그오프 | |
| 4648 | 명시적 자격증명으로 로그온(runas 등) | 내부 확산 흔적 |
| 4672 | 특수 권한 할당(관리자급 로그온) | 관리자 로그온 추적 |
| 4688 | 새 프로세스 생성 | 명령줄 감사 시 공격 명령 확인 |
| 4720 | 사용자 계정 생성 | 공격자 백도어 계정 |
| 4722 / 4725 / 4726 | 계정 활성화 / 비활성화 / 삭제 | |
| 4724 | 암호 재설정 시도 | |
| 4732 | 보안 사용 로컬 그룹에 구성원 추가 | Administrators 추가 = 권한 상승 |
| 4740 | 계정 잠김 | |
| 1102 | 감사 로그 삭제(보안 로그) | 흔적 지우기 강력 의심 |
| 7045 (System) | 새 서비스 설치 | 원격 실행 도구·악성 서비스 |
로그온 유형(Logon Type) — 4624/4625 안의 값
| 유형 | 의미 |
|---|---|
| 2 | 대화형(콘솔 직접) |
| 3 | 네트워크(공유 폴더 접근, SMB) — Pass-the-Hash도 여기 |
| 4 | 배치(예약 작업) |
| 5 | 서비스 |
| 7 | 잠금 해제 |
| 8 | NetworkCleartext (평문 자격증명, IIS 기본 인증 등) |
| 10 | RemoteInteractive(RDP 원격 데스크톱) |
| 11 | 캐시된 자격증명 |
이벤트 로그 읽기 실습
C:\> wevtutil qe Security /q:"*[System[(EventID=4625)]]" /c:3 /rd:true /f:text
Event[0]:
Log Name: Security
Event ID: 4625
Task: Logon
Description: 계정을 로그온하지 못했습니다.
...
로그온 유형: 3
실패한 계정 이름: administrator
실패 원인: 알 수 없는 사용자 이름 또는 잘못된 암호
원본 네트워크 주소: 203.0.113.45
PS> Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625} -MaxEvents 200 |
ForEach-Object { $_.Properties[19].Value } | Group-Object | Sort-Object Count -Descending
Count Name
----- ----
187 203.0.113.45 ← 한 IP에서 187회 실패 → 무차별 대입 공격
3 192.168.1.20
- 판단 흐름: 4625 다수 → 이후 같은 IP의 4624 (유형 3 또는 10) 가 있나? → 있으면 침입 성공 의심 → 4720/4732(계정 생성·관리자 그룹 추가) → 7045(서비스 설치) → 1102(로그 삭제) 순으로 타임라인 구성.
- 보안 로그 최대 크기를 충분히(예: 수십 MB 이상) 설정하고, 원격 로그 수집(SIEM) 으로 보관.
5-6. 주요 레지스트리 보안 값 정리
| 목적 | 경로 (HKLM\SYSTEM\CurrentControlSet...) | 값 |
|---|---|---|
| 기본 공유 제거(서버) | Services\LanmanServer\Parameters\AutoShareServer |
0 |
| 기본 공유 제거(PC) | Services\LanmanServer\Parameters\AutoShareWks |
0 |
| 널 세션 제한 | Control\Lsa\RestrictAnonymous |
1 |
| SAM 익명 열거 차단 | Control\Lsa\RestrictAnonymousSAM |
1 |
| LM 해시 저장 안 함 | Control\Lsa\NoLMHash |
1 |
| NTLMv2만 사용 | Control\Lsa\LmCompatibilityLevel |
5 |
| LSASS 보호(PPL) | Control\Lsa\RunAsPPL |
1 |
| WDigest 평문 캐시 금지 | Control\SecurityProviders\WDigest\UseLogonCredential |
0 |
- 자동 실행(Run) 키: 악성코드 지속성(Persistence) 의 대표 위치 → 점검 대상
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run,RunOnceHKCU\Software\Microsoft\Windows\CurrentVersion\Run- 그 외: 서비스, 예약 작업, 시작프로그램 폴더, WMI 이벤트 구독
C:\> reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
SecurityHealth REG_EXPAND_SZ %windir%\system32\SecurityHealthSystray.exe
upd REG_SZ C:\Users\Public\svch0st.exe ← ★ 의심
5-7. 패스워드 크래킹
저장된 해시에서 원래 암호를 알아내는 공격. 해시는 되돌릴 수 없으므로(일방향), 후보 암호를 해시해서 비교하는 방식이다.
| 기법 | 방법 | 장점 | 단점 |
|---|---|---|---|
| 사전 공격(Dictionary) | 자주 쓰는 단어·유출 암호 목록을 차례로 대입 | 빠름, 현실 암호에 효과적 | 목록에 없으면 실패 |
| 무차별 대입(Brute Force) | 가능한 모든 조합 시도 | 시간만 있으면 반드시 성공 | 길이·복잡도에 따라 기하급수적 시간 |
| 하이브리드 | 사전 단어 + 변형(숫자·특수문자 추가, p@ssw0rd) |
현실적 | — |
| 레인보우 테이블 | 미리 계산한 해시-평문 체인 테이블로 조회 | 크랙 시점 매우 빠름 (시간-메모리 트레이드오프) | 큰 저장 공간, 솔트에 무력 |
| 크리덴셜 스터핑 | 다른 사이트 유출 계정을 그대로 대입(온라인) | 암호 재사용 노림 | MFA·탐지에 약함 |
| 패스워드 스프레잉 | 많은 계정에 흔한 암호 하나씩(온라인) | 계정 잠금 회피 | — |
솔트(Salt)가 레인보우 테이블을 막는 원리
솔트 없음: hash("1234") = 81dc9b... ← 모든 사용자 동일
→ 미리 계산한 표 한 장으로 모두 크랙
솔트 있음: hash("x9Q2" + "1234") = 7a1f0e... (사용자 A)
hash("Lm3p" + "1234") = c42b9d... (사용자 B)
→ 같은 암호도 해시가 다르고, 솔트마다 표를 새로 만들어야 함
- 리눅스
/etc/shadow의$6$솔트$해시형식은 솔트 + SHA-512(반복 연산) — 레인보우 테이블 무력화, 연산 비용으로 무차별 대입 지연. ($1$=MD5,$5$=SHA-256,$6$=SHA-512,$y$=yescrypt) - 윈도우 NTLM 해시는 솔트가 없다 → 레인보우 테이블·PtH에 취약한 근본 이유.
- 키 스트레칭: bcrypt, scrypt, PBKDF2, Argon2 — 의도적으로 느리게.
도구
| 도구 | 특징 |
|---|---|
| John the Ripper | CPU 기반 고전 도구, 다양한 해시 자동 인식. 사전·증분(무차별) 모드. 리눅스 shadow 점검에 전통적으로 사용(unshadow 로 passwd+shadow 결합) |
| Hashcat | GPU 가속 고속 크래커. -m(해시 유형, 예: 0=MD5, 1000=NTLM, 1800=sha512crypt), -a(공격 모드: 0=사전, 3=무차별/마스크) |
| Ophcrack | 레인보우 테이블로 윈도우 LM/NTLM 크랙 |
| Hydra, Medusa | 온라인 로그인 무차별 대입(SSH, FTP, HTTP 폼) |
# 관리자의 "약한 암호 감사" 개념 예 (자기 시스템, 승인된 범위)
$ john --wordlist=common.txt --format=sha512crypt audit_hashes.txt
...
kim:summer2026 ← 약한 암호 사용자 → 변경 요구
2 password hashes cracked, 18 left
대응: 길고 복잡한 암호(패스프레이즈), 솔트 + 느린 해시, 계정 잠금(온라인 공격 대응), MFA, 해시 파일 접근 통제(shadow 400, SAM 보호), 유출 암호 목록 차단.
5-8. Pass-the-Hash 와 자격증명 탈취 (Mimikatz 개념)
Pass-the-Hash (PtH)
- NTLM 인증은 서버가 보낸 챌린지를 암호 해시로 계산해 응답한다. 즉 평문 암호가 없어도 해시만 있으면 인증 응답을 만들 수 있다.
- 공격자는 한 PC에서 탈취한 관리자 NTLM 해시를 그대로 재사용해 다른 서버에 로그온 → 크랙할 필요가 없다. APT의 내부 확산(Lateral Movement) 핵심 기법.
sequenceDiagram
participant A as 공격자(감염 PC)
participant L as LSASS 메모리
participant S as 다른 서버
A->>L: 1. 관리자 권한으로 자격증명 덤프
L-->>A: 2. 관리자 NTLM 해시 획득
A->>S: 3. 해시로 NTLM 인증 응답 생성 (평문 불필요)
S-->>A: 4. 인증 성공 → 원격 실행·확산Mimikatz (개념)
- 윈도우 LSASS(Local Security Authority Subsystem Service) 프로세스 메모리에서 평문 암호(WDigest 활성 시), NTLM 해시, Kerberos 티켓을 추출하는 것으로 잘 알려진 도구.
- 관련 공격 개념: Pass-the-Hash, Pass-the-Ticket(Kerberos 티켓 재사용), Golden Ticket(KRBTGT 계정 해시로 TGT 위조), Silver Ticket(서비스 계정 해시로 서비스 티켓 위조), Kerberoasting(서비스 티켓을 오프라인 크랙).
- 실행에는 보통 관리자(디버그 권한) 가 필요 → 로컬 관리자 권한 최소화가 1차 방어.
대응
| 대응 | 효과 |
|---|---|
| 일반 업무는 표준 계정, 관리자 권한 최소화 | 덤프 자체를 어렵게 |
| LAPS(로컬 관리자 암호 솔루션) | PC마다 로컬 관리자 암호를 다르게 → 해시 재사용 차단 |
| Credential Guard | 가상화 기반 보안(VBS)으로 자격증명 격리 |
| LSA 보호(RunAsPPL) | LSASS를 보호 프로세스로 실행 |
WDigest 비활성(UseLogonCredential=0) |
메모리에 평문 암호 미보관 |
| Protected Users 그룹, NTLM 사용 제한 → Kerberos | 해시 캐시·NTLM 사용 축소 |
| 관리 계층 분리(Tier 모델), 관리 전용 PC(PAW) | 도메인 관리자 해시가 일반 PC 메모리에 남지 않게 |
| 4624 유형 3 + 4672 이상 패턴 모니터링, EDR | 탐지 |
⚠️ 시험 함정 (Day 5)
- 기본 공유 영구 제거: 서버 AutoShareServer, PC AutoShareWks.
net share /delete는 재부팅 시 복구. - 널 세션 제한 = RestrictAnonymous(값 1 이상). "AutoShare로 널 세션 차단"은 오답.
IPC$는 기본 공유지만 삭제 대상이 아니라 익명 접근 제한 대상이다.- Administrator 이름을 바꿔도 RID 500 은 그대로.
- 1102 = 보안 감사 로그 삭제, 4625 = 실패, 4624 = 성공, 4720 = 계정 생성, 4732 = 로컬 그룹 추가. 숫자 섞기 단골.
- 로그온 유형 10 = RDP, 3 = 네트워크, 2 = 콘솔.
- 레인보우 테이블의 대응은 솔트. "계정 잠금으로 레인보우 테이블을 막는다"는 오답(레인보우는 오프라인 공격).
- 사전 공격 vs 무차별 대입: 사전은 단어 목록, 무차별은 모든 조합.
- Pass-the-Hash는 해시를 크랙하지 않는다. 해시 자체를 인증에 재사용.
- Hashcat은 GPU, John the Ripper는 전통적으로 CPU. Hydra는 온라인 대입.
- "해독 가능한 암호화를 사용하여 암호 저장" 은 사용 안 함이 양호.
기출 포인트 (Day 5)
- 레지스트리 값 이름 ↔ 기능 매칭(AutoShareServer, RestrictAnonymous, NoLMHash).
- 이벤트 ID 의미, 로그온 유형.
- 계정·암호 정책 권장 값과 secpol 항목명.
- 패스워드 크래킹 기법 설명 → 이름, 레인보우 테이블과 솔트.
- PtH 원리와 대응(실기 서술형 가능성 높음).
- 실기: 이벤트 로그 일부를 주고 공격 흐름(무차별 대입 → 성공 → 계정 생성 → 로그 삭제) 해석.
확인 문제 (Day 5)
Q1. 윈도우 서버에서 재부팅 후에도 C
① RestrictAnonymous = 1 ② AutoShareServer = 0 ③ NoLMHash = 1 ④ LmCompatibilityLevel = 5
정답: ②
- ① 틀림: 널 세션(익명 열거) 제한.
- ② 맞음:
LanmanServer\Parameters\AutoShareServer(PC는 AutoShareWks). - ③ 틀림: LM 해시 저장 안 함.
- ④ 틀림: NTLMv2만 사용하는 인증 수준.
Q2. 보안 이벤트 로그에서 공격자의 흔적 지우기를 의심할 수 있는 이벤트 ID는?
① 4624 ② 4720 ③ 4740 ④ 1102
정답: ④
- ① 로그온 성공, ② 계정 생성, ③ 계정 잠김, ④ 감사 로그가 지워짐.
Q3. 4625 이벤트를 분석한 결과 로그온 유형이 10으로 기록되어 있었다. 공격자가 시도한 접근 방식은?
① 공유 폴더(SMB) 접근 ② 원격 데스크톱(RDP) 접속 ③ 콘솔 직접 로그온 ④ 서비스 계정 시작
정답: ②
- 유형 10 = RemoteInteractive(RDP). ①은 유형 3, ③은 유형 2, ④는 유형 5.
Q4. 레인보우 테이블 공격에 대한 가장 효과적인 대응책은?
① 계정 잠금 임계값 설정 ② 해시 계산 시 사용자별 솔트 추가 ③ 로그인 화면에 마지막 사용자 이름 숨김 ④ 기본 공유 제거
정답: ②
- ① 틀림: 레인보우 테이블은 탈취한 해시를 오프라인에서 조회하므로 계정 잠금과 무관.
- ② 맞음: 솔트가 다르면 미리 계산한 테이블이 무용지물.
- ③④ 틀림: 관련 없음.
Q5. Pass-the-Hash 공격에 대한 설명으로 옳은 것은?
① 해시를 레인보우 테이블로 크랙해 평문 암호를 얻은 뒤 로그인한다 ② 평문 암호 없이 탈취한 NTLM 해시 자체를 인증에 재사용한다 ③ 솔트가 포함된 리눅스 SHA-512 해시에 주로 사용된다 ④ Kerberos 전용 인증 환경에서만 가능하다
정답: ②
- ① 틀림: 크랙이 필요 없다는 것이 핵심.
- ③ 틀림: 윈도우 NTLM 인증 대상.
- ④ 틀림: NTLM 인증에서 성립. Kerberos 티켓 재사용은 Pass-the-Ticket.
Q6. 윈도우 암호 정책 점검 결과 중 취약으로 판단해야 하는 것은?
① 암호는 복잡성을 만족해야 함: 사용 ② 최대 암호 사용 기간: 90일 ③ 해독 가능한 암호화를 사용하여 암호 저장: 사용 ④ 계정 잠금 임계값: 5
정답: ③
- ③ 은 암호를 복원 가능한 형태로 저장하는 것으로 사실상 평문 저장과 같아 사용 안 함이 양호.
- ①②④ 는 양호 기준 충족.
Day 6 · 클라우드·컨테이너 보안 (2027 신규 범위)
2027~2029 출제기준에 새로 명시된 부분. 아직 복원 기출이 거의 없으니 개념 정의와 비교를 정확히 잡는다. 첫 출제는 "용어 정의·책임 구분·도구 용도" 수준일 가능성이 높다.
6-1. 클라우드 서비스 모델과 공동 책임 모델
서비스 모델 — 피자에 비유하면 이해가 빠르다.
- On-Premise: 집에서 반죽부터 직접 (전부 내 책임)
- IaaS: 재료와 오븐을 빌림 (요리는 내가)
- PaaS: 배달 피자 (식탁·음료는 내가)
- SaaS: 레스토랑에서 먹기 (먹기만)
공동 책임 모델(Shared Responsibility Model) — "누가 무엇을 지키는가"
On-Prem IaaS PaaS SaaS
데이터·계정 [고객] [고객] [고객] [고객] ← 항상 고객
접근권한(IAM) [고객] [고객] [고객] [고객]
애플리케이션 [고객] [고객] [고객] (CSP)
런타임·미들웨어 [고객] [고객] (CSP) (CSP)
운영체제(OS) [고객] [고객] (CSP) (CSP)
가상화·하이퍼바이저[고객] (CSP) (CSP) (CSP)
서버·스토리지·망 [고객] (CSP) (CSP) (CSP)
물리 데이터센터 [고객] (CSP) (CSP) (CSP)
[고객] = 클라우드 사용자 책임 (CSP) = 클라우드 공급자 책임
| 구분 | IaaS | PaaS | SaaS |
|---|---|---|---|
| 예 | AWS EC2, Azure VM, GCP Compute Engine | AWS Elastic Beanstalk, Google App Engine, Heroku | Microsoft 365, Google Workspace, Salesforce |
| 사용자가 받는 것 | 가상 서버·네트워크·스토리지 | 앱 실행 플랫폼 | 완성된 소프트웨어 |
| OS 패치 책임 | 사용자 | 공급자 | 공급자 |
| 사용자 보안 업무 | OS 하드닝·패치, 방화벽(보안 그룹), 미들웨어, 앱, 데이터, IAM | 앱 코드 보안, 데이터, IAM, 앱 설정 | 데이터, 계정·권한, 설정(공유 범위), MFA |
- 요약 공식: "OF the cloud(클라우드 자체)는 공급자, IN the cloud(클라우드 안의 것)는 고객".
- 데이터와 계정(ID·접근 관리)은 어떤 모델이든 고객 책임이다. SaaS라도 "전체 공개" 공유 설정 실수는 사용자 탓.
- 배포 모델: 퍼블릭 / 프라이빗 / 하이브리드 / 멀티 클라우드 / 커뮤니티.
6-2. 클라우드 운영체계: 가상화와 하이퍼바이저
가상화: 하나의 물리 서버 위에서 여러 개의 독립된 가상 머신(VM)을 돌리는 기술. 각 VM은 자기만의 게스트 OS 를 가진다. 이를 관리하는 소프트웨어가 하이퍼바이저(VMM, Virtual Machine Monitor).
[Type 1: 베어메탈(네이티브)] [Type 2: 호스트형]
┌──────┐┌──────┐┌──────┐ ┌──────┐┌──────┐
│ VM1 ││ VM2 ││ VM3 │ │ VM1 ││ VM2 │
│게스트OS││게스트OS││게스트OS│ │게스트OS││게스트OS│
└──────┘└──────┘└──────┘ └──────┘└──────┘
┌──────────────────────┐ ┌──────────────────┐
│ 하이퍼바이저 │ │ 하이퍼바이저(앱) │
└──────────────────────┘ ├──────────────────┤
┌──────────────────────┐ │ 호스트 OS │
│ 하드웨어 │ ├──────────────────┤
└──────────────────────┘ │ 하드웨어 │
└──────────────────┘
| 구분 | Type 1 (베어메탈) | Type 2 (호스트형) |
|---|---|---|
| 위치 | 하드웨어 위에 직접 | 호스트 OS 위의 응용 프로그램 |
| 예 | VMware ESXi, Microsoft Hyper-V, Xen, KVM(리눅스 커널 통합) | VMware Workstation, VirtualBox, Parallels |
| 성능 | 높음(중간 OS 없음) | 낮음(호스트 OS 경유) |
| 보안 | 공격 표면 작음 | 호스트 OS 취약점도 영향 |
| 용도 | 클라우드·데이터센터 | 개인 PC 테스트·실습 |
전가상화 vs 반가상화
- 전가상화(Full): 게스트 OS 수정 없이 실행(하드웨어 지원 VT-x/AMD-V 또는 바이너리 변환).
- 반가상화(Para): 게스트 OS를 수정해 하이퍼바이저와 직접 통신(하이퍼콜) → 성능↑. 대표 Xen.
가상화 보안 위협
- VM 이스케이프(VM Escape): VM 안에서 하이퍼바이저 취약점을 이용해 호스트나 다른 VM 으로 탈출 → 멀티 테넌트 클라우드에서 최악의 시나리오.
- VM 스프롤(Sprawl): 관리 안 되는 VM이 늘어나 패치 누락.
- 하이퍼재킹: 하이퍼바이저 자체 장악.
- VM 간 사이드채널(캐시 타이밍 등), 스냅샷·이미지에 남은 민감 정보.
6-3. 컨테이너 vs VM
컨테이너: 앱과 그 실행에 필요한 라이브러리만 묶어(이미지) 호스트 OS의 커널을 공유하며 격리 실행하는 기술(Docker, containerd, Kubernetes가 오케스트레이션).
[가상 머신] [컨테이너]
┌─────┐┌─────┐┌─────┐ ┌─────┐┌─────┐┌─────┐
│ App ││ App ││ App │ │ App ││ App ││ App │
│ Lib ││ Lib ││ Lib │ │ Lib ││ Lib ││ Lib │
│GuestOS││GuestOS││GuestOS│ └─────┘└─────┘└─────┘
└─────┘└─────┘└─────┘ ┌──────────────────┐
┌──────────────────┐ │ 컨테이너 런타임 │
│ 하이퍼바이저 │ ├──────────────────┤
├──────────────────┤ │ 호스트 OS (커널 공유) │ ★
│ 하드웨어 │ ├──────────────────┤
└──────────────────┘ │ 하드웨어 │
└──────────────────┘
| 구분 | VM | 컨테이너 |
|---|---|---|
| 격리 단위 | 하드웨어 수준(하이퍼바이저) | OS(커널) 수준(프로세스 격리) |
| 커널 | VM마다 독립 | 호스트 커널 공유 |
| 크기·속도 | GB 단위, 부팅 수십 초~분 | MB 단위, 시작 수 초 이하 |
| 격리 강도 | 강함 | 상대적으로 약함 — 커널 취약점 1개로 모든 컨테이너 위험 |
리눅스 컨테이너 격리 기술
| 기술 | 역할 |
|---|---|
| Namespace | "보이는 것"을 격리 — PID(프로세스), NET(네트워크), MNT(파일시스템), UTS(호스트명), IPC, USER(UID 매핑) |
| cgroups | "쓸 수 있는 양"을 제한 — CPU, 메모리, I/O (자원 고갈 DoS 방지) |
| Capabilities | root 권한을 잘게 쪼개 필요한 것만 부여(예: CAP_NET_BIND_SERVICE) |
| seccomp | 허용된 시스템 콜만 사용 |
| SELinux/AppArmor | 컨테이너 프로세스에 MAC 적용(Day 1) |
--privileged 컨테이너의 위험
docker run --privileged는 모든 Capability를 부여하고 호스트 장치(/dev) 접근을 허용하며 seccomp·AppArmor 같은 제한을 대부분 해제한다.- 결과: 컨테이너 안의 root ≈ 호스트 root → 호스트 디스크 마운트, 커널 모듈 적재 등으로 컨테이너 탈출이 쉬워진다.
- 비슷하게 위험한 설정:
/var/run/docker.sock마운트(컨테이너가 도커 데몬을 조종 → 새 privileged 컨테이너 생성 가능),--pid=host,--net=host, 호스트 루트(/) 마운트,CAP_SYS_ADMIN부여.
컨테이너 보안 수칙
- root가 아닌 사용자로 실행(
USER 1000in Dockerfile), privileged 금지, Capability 최소화(--cap-drop ALL후 필요한 것만 add). - 신뢰할 수 있는 최소 베이스 이미지(distroless, alpine 등), 이미지 취약점 스캔(Trivy), 이미지 서명.
- 이미지에 비밀번호·API 키 하드코딩 금지 → 시크릿 관리 서비스 사용.
- 읽기 전용 루트 파일시스템(
--read-only), 자원 제한(cgroups). - Kubernetes: RBAC 최소 권한, Pod Security Standards(privileged 금지), 네트워크 정책.
6-4. 인스턴스 메타데이터와 IMDSv2
인스턴스 메타데이터 서비스(IMDS)
- 클라우드 VM(인스턴스) 내부에서만 접근 가능한 특수 주소
169.254.169.254(링크 로컬)로, 자기 자신에 대한 정보를 조회하는 서비스. - 들어있는 정보: 인스턴스 ID, 사설 IP, 호스트명, 보안 그룹, 사용자 데이터(user-data, 초기화 스크립트 — 비밀번호를 넣는 실수 잦음), 그리고 가장 중요한 IAM 역할의 임시 자격증명(AccessKeyId, SecretAccessKey, Token).
- 비유: 호텔 객실 안의 인터폰. 방 안에서는 프런트에 "내 방 마스터키 하나 더 주세요"라고 할 수 있다. 문제는, 손님이 아닌 누군가가 그 인터폰을 대신 눌러 달라고 손님(서버)을 속이는 것.
SSRF → 메타데이터 탈취 흐름
SSRF(Server-Side Request Forgery): 웹 애플리케이션이 사용자가 준 URL로 서버가 대신 요청하는 기능(이미지 URL 미리보기, 웹훅 등)을 악용해, 외부에서 직접 못 가는 내부 주소에 요청하게 만드는 공격.
sequenceDiagram
participant A as 공격자
participant W as 웹 앱(EC2 인스턴스)
participant M as IMDS 169.254.169.254
participant S as 클라우드 API(스토리지 등)
A->>W: 1. url=http://169.254.169.254/... 입력
W->>M: 2. 서버가 대신 메타데이터 요청 (IMDSv1: 단순 GET)
M-->>W: 3. IAM 역할 임시 자격증명 반환
W-->>A: 4. 응답 내용을 그대로 공격자에게 표시
A->>S: 5. 탈취한 자격증명으로 API 호출(데이터 유출)- 실제 사례: 2019년 미국 금융사 대규모 유출 — 잘못 구성된 WAF의 SSRF → IMDSv1 → IAM 역할 자격증명 → 스토리지 버킷 대량 유출. 과도한 IAM 권한이 피해를 키웠다.
IMDSv1 vs IMDSv2
| 구분 | IMDSv1 | IMDSv2 |
|---|---|---|
| 방식 | 단순 HTTP GET (요청-응답) | 세션 지향: 먼저 PUT 으로 토큰 발급 → 이후 GET 요청 헤더에 토큰 포함 |
| SSRF 내성 | 약함(URL만 조종하면 됨) | 강함 — 대부분의 SSRF는 PUT 메서드·사용자 정의 헤더를 못 만든다 |
| 추가 보호 | — | 응답 홉 제한(TTL, 기본 1) 으로 네트워크 밖·중첩 컨테이너 전달 제한, X-Forwarded-For 포함 요청 거부 |
# IMDSv2 사용 흐름 (인스턴스 내부에서의 정상 사용 예)
$ TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
$ curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/instance-id
i-0abc123def4567890
# 토큰 없이 요청 (IMDSv2 필수 설정 시)
$ curl -s -o /dev/null -w "%{http_code}\n" http://169.254.169.254/latest/meta-data/
401
대응
- IMDSv2 강제(HttpTokens = required), 필요 없으면 IMDS 비활성.
- 애플리케이션 SSRF 방어: 요청 URL 화이트리스트, 내부·링크로컬 IP(169.254.0.0/16, 10.0.0.0/8 등) 차단, 리다이렉트 재검증.
- 인스턴스 IAM 역할 최소 권한(탈취돼도 피해 최소화).
- user-data에 비밀 정보 넣지 않기.
- 클라우드 감사 로그로 비정상 위치에서 자격증명 사용 탐지.
6-5. 클라우드 시스템 정보와 감사 로그
출제기준의 "시스템 정보 – 클라우드 인스턴스 메타데이터·설정·감사 로그"에 해당.
| 정보 종류 | 무엇 | 예 |
|---|---|---|
| 메타데이터 | 인스턴스 자신의 정보·임시 자격증명 | IMDS (6-4) |
| 설정(구성) 정보 | 리소스 구성 상태·변경 이력 | AWS Config, Azure Policy, GCP Cloud Asset Inventory |
| 감사 로그 | 누가·언제·어디서·어떤 API를·어떤 결과로 호출 | AWS CloudTrail, Azure Activity Log(+ Entra ID 로그), GCP Cloud Audit Logs |
| 네트워크 흐름 로그 | 트래픽 메타데이터 | VPC Flow Logs, NSG Flow Logs |
| OS·앱 로그 | 인스턴스 내부 로그 | CloudWatch Logs, Azure Monitor |
CloudTrail 이벤트 예 (개념)
{
"eventTime": "2026-12-30T02:14:09Z",
"eventSource": "s3.amazonaws.com",
"eventName": "PutBucketPolicy",
"userIdentity": { "type": "IAMUser", "userName": "dev-kim" },
"sourceIPAddress": "198.51.100.23",
"requestParameters": { "bucketName": "corp-backup" },
"responseElements": null
}
→ "dev-kim 이 새벽 2시에 처음 보는 IP에서 백업 버킷 정책을 변경" = 공개 전환 시도 여부 확인 필요.
주목할 이벤트 패턴
StopLogging,DeleteTrail(감사 로그 끄기 — 윈도우 1102 와 같은 의미의 흔적 지우기)ConsoleLogin실패 반복, MFA 없는 root 계정 로그인CreateAccessKey,AttachUserPolicy(관리자 정책 부여) — 권한 상승·지속성AuthorizeSecurityGroupIngress로 0.0.0.0/0 개방PutBucketPolicy/PutBucketAcl로 공개 설정
감사 로그 보호: 모든 리전 활성화, 별도 보안 계정의 스토리지에 저장, 무결성 검증(다이제스트 파일), 삭제 방지(객체 잠금), SIEM 연동.
6-6. 클라우드·컨테이너 보안 위협: 구성 오류와 과도한 권한
클라우드 사고의 대부분은 공급자 해킹이 아니라 고객의 잘못된 설정(Misconfiguration) 에서 나온다.
| 유형 | 사례 | 대응 |
|---|---|---|
| 공개 스토리지 | 버킷·블롭을 "퍼블릭 읽기"로 설정 → 개인정보 노출 | 퍼블릭 액세스 차단(계정 수준), 정책 점검 |
| 과도한 네트워크 허용 | 보안 그룹 0.0.0.0/0 으로 SSH(22)·RDP(3389)·DB(3306) 개방 | 출발지 IP 제한, 배스천·VPN·세션 관리자 |
| 과도한 IAM 권한 | 정책에 "Action": "*", "Resource": "*", 개발자 계정에 관리자 권한 |
최소 권한, 역할 기반, 권한 경계, 미사용 권한 정리 |
| root 계정 사용 | 클라우드 최상위(root) 계정으로 일상 작업, MFA 없음 | root 잠금 + MFA, 개별 IAM 사용자/SSO |
| 키 하드코딩·유출 | 액세스 키를 소스 코드·공개 저장소·이미지에 포함 | 시크릿 매니저, 임시 자격증명(역할), 키 순환, 시크릿 스캔 |
| 로깅 비활성 | 감사 로그 꺼짐 → 사고 조사 불가 | 전 리전 감사 로그, 변경 알림 |
| 암호화 미적용 | 디스크·스냅샷·DB 미암호화, 스냅샷 공개 공유 | 기본 암호화, KMS |
| 컨테이너 | privileged, root 실행, docker.sock 마운트, 취약한 이미지, K8s 대시보드 무인증 노출 | 6-3 수칙, 이미지 스캔 |
| IaC 오류 | Terraform·CloudFormation 템플릿에 위 설정이 박혀 대량 복제 | IaC 스캔(배포 전 점검) |
과도한 권한 예 (IAM 정책)
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "*", ← 모든 작업
"Resource": "*" ← 모든 리소스 → 취약
}]
}
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["s3:GetObject"], ← 필요한 작업만
"Resource": "arn:aws:s3:::app-assets/*" ← 필요한 대상만 → 양호
}]
}
클라우드 보안 솔루션 용어
| 용어 | 의미 |
|---|---|
| CSPM (Cloud Security Posture Management) | 클라우드 설정 상태를 지속 점검해 구성 오류 탐지 (ScoutSuite가 이 성격) |
| CWPP (Cloud Workload Protection Platform) | VM·컨테이너·서버리스 워크로드 보호 (취약점, 런타임 탐지) |
| CIEM | 클라우드 권한(ID) 관리, 과도한 권한 탐지 |
| CNAPP | CSPM + CWPP + CIEM 등을 통합한 플랫폼 |
| CASB | 사용자와 SaaS 사이에서 가시성·정책 적용 |
6-7. Trivy — 컨테이너·IaC 취약점 스캐너
Trivy (Aqua Security, 오픈소스)
- 스캔 대상: 컨테이너 이미지, 파일시스템, Git 저장소, IaC 파일(Terraform, CloudFormation, Dockerfile, Kubernetes YAML), Kubernetes 클러스터, VM 이미지, SBOM.
- 찾는 것: 알려진 취약점(CVE) — OS 패키지·언어별 라이브러리, 설정 오류(Misconfiguration), 시크릿(하드코딩된 키), 라이선스.
- 쓰임: 이미지 빌드 후 CI/CD 파이프라인에서 자동 스캔 → CRITICAL이 있으면 배포 차단 (Shift-Left, 개발 초기에 보안 점검).
$ trivy image --severity HIGH,CRITICAL myapp:1.0
myapp:1.0 (alpine 3.15.0)
==========================
Total: 3 (HIGH: 3, CRITICAL: 0)
┌──────────────┬────────────────┬──────────┬───────────┬───────────┐
│ Library │ Vulnerability │ Severity │ Installed │ Fixed │
├──────────────┼────────────────┼──────────┼───────────┼───────────┤
│ libcrypto1.1 │ CVE-2022-0778 │ HIGH │ 1.1.1l-r7 │ 1.1.1n-r0 │
│ libssl1.1 │ CVE-2022-0778 │ HIGH │ 1.1.1l-r7 │ 1.1.1n-r0 │
│ zlib │ CVE-2018-25032 │ HIGH │ 1.2.11-r3 │ 1.2.12-r0 │
└──────────────┴────────────────┴──────────┴───────────┴───────────┘
(출력 형식 예시 — 버전·등급은 DB 갱신에 따라 달라질 수 있음)
결과 읽는 법
- Installed: 이미지에 들어있는 버전 / Fixed: 패치된 버전 → 베이스 이미지를 최신으로 올리거나 패키지 업데이트 후 재빌드.
- Fixed가 비어 있으면 아직 패치 없음 → 위험 수용·완화 조치 판단.
$ trivy config ./terraform/ # IaC 설정 오류
$ trivy fs --scanners secret ./src # 소스에 박힌 시크릿
$ trivy image --exit-code 1 --severity CRITICAL myapp:1.0
# → CRITICAL 이 있으면 종료코드 1 → CI 파이프라인 실패 처리
# trivy config 결과 예 (Dockerfile)
Dockerfile (dockerfile)
Tests: 21 (SUCCESSES: 19, FAILURES: 2)
Failures: 2 (HIGH: 1, MEDIUM: 1)
HIGH: Specify at least 1 USER command in Dockerfile with non-root user
MEDIUM: Specify a tag in the 'FROM' statement for image 'ubuntu'
→ 컨테이너가 root로 실행되는 설정, latest 태그 사용 지적.
6-8. ScoutSuite — 멀티 클라우드 보안 감사 도구
ScoutSuite (NCC Group, 오픈소스, Python)
- 대상: AWS, Azure, GCP, Alibaba Cloud, Oracle Cloud 등 멀티 클라우드.
- 방식: 클라우드 API로 설정 정보를 읽어(Read-only 권한) 수집 → 보안 규칙과 비교 → HTML 보고서로 위험 항목 표시. 에이전트 설치 불필요, 리소스를 변경하지 않음.
- 성격: CSPM(구성 상태 점검) 도구 — Trivy가 "이미지·코드 안"을 본다면 ScoutSuite는 "클라우드 계정의 설정"을 본다.
$ scout aws --profile audit-readonly
[...] Fetching resources for the IAM service
[...] Fetching resources for the EC2 service
[...] Fetching resources for the S3 service
...
[...] Saving data to scoutsuite-report/scoutsuite-results/...
[...] Report: scoutsuite-report/aws-audit-readonly.html
보고서에서 보이는 항목 예
| 서비스 | 발견 항목(예) | 위험도 |
|---|---|---|
| IAM | Root account without MFA | 위험 |
| IAM | Users with AdministratorAccess / Inline policy *:* |
위험 |
| EC2 | Security group allows 0.0.0.0/0 on port 22 | 위험 |
| S3 | Bucket world-readable / 암호화 없음 / 로깅 없음 | 위험·경고 |
| CloudTrail | Not enabled in all regions | 경고 |
도구 비교
| 도구 | 대상 | 주 용도 | 비유 |
|---|---|---|---|
| Nmap | 네트워크·호스트 | 열린 포트·서비스·OS 탐지 | 건물 바깥에서 열린 창문 세기 |
| Trivy | 컨테이너 이미지·IaC·파일시스템 | CVE·설정 오류·시크릿 | 상자(이미지) 속 부품 검사 |
| ScoutSuite | 클라우드 계정(API) | 구성 오류·과도한 권한 감사 | 건물 관리 규정 준수 점검 |
| Tripwire/AIDE | 호스트 파일 | 무결성(변조) 탐지 | 봉인 스티커 확인 |
⚠️ 시험 함정 (Day 6)
- IaaS에서 게스트 OS 패치는 사용자 책임. "IaaS의 OS 패치는 공급자 책임"은 오답.
- 데이터와 접근 권한(계정)은 SaaS에서도 고객 책임.
- Type 1 = 하드웨어 위 직접(ESXi, Hyper-V, Xen), Type 2 = 호스트 OS 위(VirtualBox, VMware Workstation).
- 컨테이너는 커널을 공유하므로 VM보다 격리가 약하다. "컨테이너가 VM보다 격리 강도가 높다"는 오답.
- Namespace = 격리(보이는 범위), cgroups = 자원 제한. 둘을 바꿔 낸 보기 주의.
--privileged는 보안 강화 옵션이 아니라 위험한 설정.- 메타데이터 주소는 169.254.169.254(링크 로컬). 사설 대역 10.x 아님.
- IMDSv2의 핵심은 세션 토큰(PUT으로 발급). "IMDSv2는 HTTPS 암호화가 핵심"은 오답.
- 감사 로그(CloudTrail 등)는 API 호출 기록(누가·무엇을). 네트워크 패킷 내용 기록이 아니다(그건 흐름 로그도 메타데이터 수준).
- Trivy = 이미지·IaC 취약점 스캐너, ScoutSuite = 클라우드 설정 감사. 용도 바꿔 내기 주의.
기출 포인트 (Day 6) — 예상
- 서비스 모델별 책임 주체 고르기(IaaS/PaaS/SaaS 표).
- 하이퍼바이저 유형 구분, 컨테이너와 VM 비교.
- 메타데이터 서비스 + SSRF 시나리오 → 대응(IMDSv2, 최소 권한).
- 클라우드 구성 오류 사례 고르기, 과도한 권한(privileged,
*:*). - 도구 용도 매칭: Nmap / Trivy / ScoutSuite.
- 실기: "컨테이너 이미지 보안 점검 방법", "클라우드 감사 로그의 역할" 서술 가능성.
확인 문제 (Day 6)
Q1. 클라우드 공동 책임 모델에서 IaaS 환경의 고객 책임에 해당하지 않는 것은?
① 게스트 OS 보안 패치 ② 보안 그룹(가상 방화벽) 규칙 설정 ③ 하이퍼바이저 취약점 패치 ④ 저장 데이터 암호화
정답: ③
- ③ 하이퍼바이저와 물리 인프라는 공급자(CSP) 책임.
- ①②④ 는 IaaS에서 고객 책임.
Q2. 다음 중 Type 2(호스트형) 하이퍼바이저에 해당하는 것은?
① VMware ESXi ② Xen ③ Oracle VirtualBox ④ Microsoft Hyper-V
정답: ③
- VirtualBox는 호스트 OS(Windows, macOS, Linux) 위에 설치되는 응용 프로그램형.
- ①②④ 는 하드웨어 위에서 직접 동작하는 Type 1.
Q3. 컨테이너 보안에 대한 설명으로 옳지 않은 것은?
① 컨테이너는 호스트 커널을 공유하므로 커널 취약점의 영향을 받는다 ② cgroups는 컨테이너의 CPU·메모리 사용량을 제한한다 ③ --privileged 옵션은 컨테이너의 권한을 최소화해 탈출 위험을 줄인다 ④ 컨테이너는 root가 아닌 사용자로 실행하는 것이 권장된다
정답: ③
- ③ 틀림: privileged 는 모든 Capability와 장치 접근을 허용해 탈출 위험을 크게 높인다.
- ①②④ 맞음.
Q4. 웹 애플리케이션의 SSRF 취약점을 이용해 클라우드 인스턴스의 IAM 임시 자격증명이 유출되었다. 인스턴스 측에서 가장 직접적인 재발 방지 조치는?
① 인스턴스의 디스크 암호화 ② IMDSv2(세션 토큰 필수) 적용 ③ 인스턴스 유형을 더 큰 사양으로 변경 ④ 웹 서버의 로그 보관 기간 연장
정답: ②
- IMDSv2는 PUT 요청으로 받은 토큰을 헤더에 넣어야만 메타데이터를 주므로, 단순 GET만 가능한 SSRF로는 접근이 어렵다. 함께 SSRF 입력 검증, IAM 최소 권한도 필요.
- ①③④ 는 메타데이터 탈취와 무관.
Q5. 클라우드 환경에서 "누가, 언제, 어떤 API를 호출했는지"를 기록하는 서비스는?
① VPC Flow Logs ② AWS CloudTrail ③ 인스턴스 메타데이터 서비스 ④ 컨테이너 레지스트리
정답: ②
- ① 틀림: 네트워크 트래픽 흐름 기록.
- ② 맞음: API 호출 감사 로그. Azure는 Activity Log, GCP는 Cloud Audit Logs.
- ③ 틀림: 인스턴스 자기 정보 조회.
- ④ 틀림: 이미지 저장소.
Q6. 도구와 주된 용도의 연결로 옳지 않은 것은?
① Trivy – 컨테이너 이미지의 알려진 취약점(CVE) 스캔 ② ScoutSuite – 멀티 클라우드 계정의 보안 설정 감사 ③ Nmap – 대상 호스트의 열린 포트와 서비스 탐지 ④ ScoutSuite – 실행 중인 컨테이너 내부 메모리의 악성코드 분석
정답: ④
- ScoutSuite는 클라우드 API로 설정을 읽어 구성 오류를 보고하는 CSPM 성격의 도구다. 메모리 악성코드 분석 도구가 아니다.
Day 7 · 주간 정리
7-1. 한 장 총정리
Day 1 운영체제 · 보안 OS
- OS 4대 관리: 프로세스·메모리·파일·장치. 커널(Ring 0) / 쉘(명령 해석) / 시스템 콜(유일한 창구).
- 프로세스 상태: 준비 →(디스패치)→ 실행 →(타임아웃)→ 준비, 실행 →(블록)→ 대기 →(웨이크업)→ 준비.
- 메모리: Text / Data / BSS / Heap(↑) / Stack(↓). 페이징=내부 단편화, 세그먼테이션=외부 단편화.
- 참조 모니터(개념) → 보안 커널(구현) ⊂ TCB(전체). 3조건: 완전 중재·격리·검증 가능.
- 보안 OS = MAC, 객체 재사용 방지, 감사, 신뢰 경로. SELinux: Enforcing(차단+기록) / Permissive(기록만) / Disabled.
- TCSEC D·C1·C2(감사)·B1(레이블 MAC)·B2·B3(참조 모니터)·A1(정형 검증). ITSEC=기능·보증 분리. CC=ISO 15408, PP(공통)·ST(제품)·TOE·EAL1~7.
Day 2 메모리 공격
- 스택 BOF: 버퍼 → SFP → RET 덮음. 힙 BOF: 함수 포인터·청크 메타데이터.
- 안전 함수: strcpy→strncpy/strlcpy, gets→fgets, sprintf→snprintf (strncpy는 NULL 종료 직접).
- 방어: Canary(검사값), Stack Shield(RET 사본), ASLR(주소 랜덤,
randomize_va_space=2), DEP/NX(실행 금지). 우회: RTL·ROP(NX 우회). - 포맷 스트링:
printf(buf)→%x읽기 /%n쓰기 →printf("%s", buf). - 레이스 컨디션(TOCTOU): 임시 파일 + 심볼릭 링크 →
mkstemp,O_EXCL,O_NOFOLLOW, sticky bit. - 정수 오버플로: 범위 초과 wrap → 길이 검사 우회 → BOF.
Day 3 악성코드 · 사회공학
- 바이러스(기생+복제) / 웜(독립+네트워크 전파) / 트로이(위장, 비복제) / 루트킷(은닉+권한 유지, 커널형 탐지 난이도↑).
- 바이러스 세대: 원시 → 암호(루틴 고정) → 은폐(스텔스) → 갑옷·다형성(루틴까지 변형) → 매크로.
- 랜섬웨어(3-2-1 백업), 봇넷(C&C, P2P), 파일리스(LotL, PowerShell → 행위 탐지).
- 분석: 정적(실행 X, strings·디스어셈블) / 동적(실행, 샌드박스·디버깅). 탐지: 시그니처·휴리스틱·행위.
- EPP(예방) / EDR(탐지·대응, 행위 기록·격리) / XDR(통합).
- 피싱(불특정) / 스피어(특정) / 웨일링(임원) / 파밍(정상 주소 → 가짜, DNS·hosts) / 스미싱(SMS) / 큐싱(QR) / 비싱(음성) / 워터링 홀(자주 가는 사이트).
- APT: 정찰 → 침투 → 거점 → 확산 → 수집 → 유출. 킬 체인: 정찰·무기화·전달·익스플로잇·설치·C2·목적 달성.
Day 4 리눅스 점검 · Nmap
- 계정:
PermitRootLogin no, securetty pts 제거, pwquality·login.defs, faillock deny, shadow(x), UID 0,pam_wheel+su 4750, nologin. - 파일: PATH의
., passwd 644 / shadow 400 / hosts 600 / inetd.conf 600 / syslog.conf 640, SUID(-perm -4000), World Writable(-perm -2), nouser, umask 022. - 서비스: r 계열(.rhosts·hosts.equiv
+위험), finger·tftp·echo·chargen, TCP Wrapper(allow→deny, 둘 다 없으면 허용), cron.allow 우선. - Tripwire/AIDE: 클린 상태에서 기준 DB(해시) → 주기 점검 → 정상 변경 시 갱신.
- Nmap:
-sT완전 연결,-sSHalf-open,-sF/-sX/-sN(열림=무응답, 닫힘=RST),-sA방화벽 확인,-sU(닫힘=ICMP Unreachable),-sV,-O,-Pn.
Day 5 윈도우
- Administrator 이름 변경(RID 500 그대로), Guest 비활성, 잠금 임계값, 복잡성, 해독 가능 암호화 X, LM 해시 저장 X(NoLMHash=1), NTLMv2만(Level 5).
- 기본 공유: AutoShareServer/Wks=0, 널 세션: RestrictAnonymous=1.
- 이벤트: 4624 / 4625 / 4672 / 4688 / 4720 / 4732 / 4740 / 1102 / 7045. 로그온 유형 2 콘솔, 3 네트워크, 10 RDP.
- 크래킹: 사전 / 무차별 / 레인보우(솔트로 대응). John(CPU), Hashcat(GPU), Hydra(온라인).
- PtH: NTLM 해시 재사용(크랙 불필요). LSASS 덤프(Mimikatz 개념) → LAPS, Credential Guard, RunAsPPL, 최소 권한.
Day 6 클라우드 · 컨테이너
- IaaS(사용자: OS부터) / PaaS(앱·데이터) / SaaS(데이터·계정·설정). 데이터·계정은 항상 고객.
- 하이퍼바이저 Type1(ESXi·Hyper-V·Xen·KVM) / Type2(VirtualBox·Workstation). VM escape.
- 컨테이너: 커널 공유(격리 약함), Namespace(격리)·cgroups(자원)·Capabilities·seccomp. privileged·docker.sock 위험.
- IMDS 169.254.169.254 → SSRF로 IAM 자격증명 탈취 → IMDSv2(PUT 토큰) + 최소 권한.
- 감사 로그: CloudTrail / Azure Activity Log / GCP Cloud Audit Logs. StopLogging = 흔적 지우기.
- 구성 오류: 공개 버킷, 0.0.0.0/0,
*:*, root 무MFA, 키 하드코딩. CSPM/CWPP/CIEM/CNAPP. - Trivy(이미지·IaC·시크릿 CVE 스캔) / ScoutSuite(멀티 클라우드 설정 감사, 읽기 전용 API, HTML 보고서).
7-2. 헷갈리는 쌍 비교 모음
| 헷갈리는 쌍 | 구분 포인트 |
|---|---|
| 참조 모니터 vs 보안 커널 | 개념 vs 구현 |
| Stack Guard vs Stack Shield | 카나리 vs RET 사본 |
| ASLR vs DEP | 주소 랜덤 vs 실행 금지 |
| mktemp vs mkstemp | 이름만 vs 안전 생성 |
| 바이러스 vs 웜 | 숙주 필요 vs 독립 전파 |
| 피싱 vs 파밍 | 링크 클릭 vs 정상 주소 입력 |
| 스피어 피싱 vs 웨일링 | 특정인 vs 고위층 |
| 정적 vs 동적 분석 | 실행 X vs 실행 O |
| EPP vs EDR | 예방 vs 탐지·대응 |
| 사용자 vs 커널 루트킷 | 바이너리 교체 vs 커널 후킹 |
| SYN vs Connect 스캔 | 반만 연결 vs 완전 연결 |
| AutoShareServer vs RestrictAnonymous | 기본 공유 vs 널 세션 |
| 레인보우 테이블 vs PtH | 해시 → 평문(크랙) vs 해시 그대로 사용 |
| Type 1 vs Type 2 | 하드웨어 위 vs 호스트 OS 위 |
| Namespace vs cgroups | 격리 vs 자원 제한 |
| Trivy vs ScoutSuite | 이미지·코드 vs 클라우드 계정 설정 |
7-3. 미니 모의고사 (20문항)
시간 재고 풀기: 20분. 다 푼 뒤 정답을 펼친다. 틀린 문제는 아래 오답 노트에 기록.
M1. 참조 모니터를 실제로 구현한 하드웨어·펌웨어·소프트웨어를 무엇이라 하는가?
① TCB ② 보안 커널 ③ 보안 경계 ④ 신뢰 경로
M2. TCSEC에서 개별 사용자 책임 추적을 위한 감사(Audit) 기능이 처음 요구되는 등급은?
① C1 ② C2 ③ B1 ④ B2
M3. CC(공통평가기준)에 대한 설명으로 옳지 않은 것은?
① 국제 표준 ISO/IEC 15408이다 ② 보증 등급은 EAL1~EAL7이다 ③ ST는 제품 유형별로 구현 독립적인 요구사항을 정의한다 ④ TOE는 평가 대상 제품이다
M4. 다음 중 버퍼 오버플로에 취약한 함수와 대체 함수의 연결이 옳지 않은 것은?
① strcpy – strncpy ② gets – fgets ③ sprintf – snprintf ④ fgets – gets
M5. 지역 변수와 리턴 주소 사이에 임의의 값을 두고 함수 종료 전에 변경 여부를 검사하는 기법은?
① ASLR ② NX bit ③ Stack Canary ④ RELRO
M6. 메모리의 스택·힙 영역에 있는 코드의 실행을 막는 기법을 우회하기 위해 기존 코드 조각(가젯)을 연결해 실행 흐름을 만드는 기법은?
① ROP ② NOP sled ③ 힙 스프레이 ④ 포맷 스트링
M7. 포맷 스트링 공격에서 지금까지 출력된 바이트 수를 지정된 주소에 기록해 메모리 변조에 사용되는 지정자는?
① %x ② %s ③ %d ④ %n
M8. 임시 파일 생성과 사용 사이의 시간 차를 이용해 심볼릭 링크로 다른 파일을 덮어쓰게 하는 공격은?
① 정수 오버플로 ② 레이스 컨디션 ③ 힙 스프레이 ④ 사전 공격
M9. 다음 중 자기 복제 기능이 없는 악성코드는?
① 웜 ② 매크로 바이러스 ③ 트로이목마 ④ 부트 바이러스
M10. 감염 사실을 숨기기 위해 파일 크기나 날짜를 감염 전 정보로 보여 주는 바이러스 세대는?
① 원시형 ② 암호형 ③ 은폐형 ④ 매크로
M11. 특정 집단이 자주 방문하는 웹사이트를 미리 감염시켜 방문자를 공격하는 기법은?
① 파밍 ② 워터링 홀 ③ 스미싱 ④ 웨일링
M12. 악성코드를 실행하지 않고 문자열, PE 헤더, 디스어셈블 코드를 통해 분석하는 방법은?
① 동적 분석 ② 샌드박스 분석 ③ 정적 분석 ④ 행위 분석
M13. 리눅스에서 SSH를 통한 root 직접 로그인을 막기 위한 sshd_config 설정은?
① PermitEmptyPasswords no ② PermitRootLogin no ③ PasswordAuthentication yes ④ UsePAM no
M14. TCP Wrapper에서 hosts.allow 와 hosts.deny 어디에도 매칭되지 않은 접속의 처리는?
① 거부된다 ② 허용된다 ③ 로그만 남기고 거부된다 ④ 관리자 승인 대기
M15. umask 가 077 일 때 새로 생성되는 디렉터리의 권한은?
① 700 ② 600 ③ 755 ④ 644
M16. Nmap 스캔 중 3-way handshake를 완료하지 않고 SYN/ACK 수신 시 RST를 보내 연결을 끊는 방식은?
① -sT ② -sS ③ -sU ④ -sA
M17. 윈도우에서 익명 사용자(널 세션)의 SAM 계정·공유 열거를 제한하는 레지스트리 값은?
① AutoShareWks ② RestrictAnonymous ③ NoLMHash ④ UseLogonCredential
M18. 탈취한 NTLM 해시를 크랙하지 않고 그대로 인증에 사용하는 공격은?
① 레인보우 테이블 공격 ② Pass-the-Hash ③ 크리덴셜 스터핑 ④ 패스워드 스프레잉
M19. 컨테이너 격리 기술 중 프로세스·네트워크·마운트 등 "보이는 범위"를 분리하는 것은?
① cgroups ② Namespace ③ seccomp ④ Capabilities
M20. 클라우드 인스턴스 메타데이터 서비스에 대한 설명으로 옳지 않은 것은?
① 인스턴스 내부에서 169.254.169.254 로 접근한다 ② IAM 역할의 임시 자격증명이 포함될 수 있다 ③ IMDSv2는 PUT으로 발급받은 세션 토큰을 요구한다 ④ IMDSv2를 적용하면 SSRF 취약점 자체가 웹 애플리케이션에서 제거된다
| 번호 | 정답 | 번호 | 정답 |
|---|---|---|---|
| M1 | ② | M11 | ② |
| M2 | ② | M12 | ③ |
| M3 | ③ | M13 | ② |
| M4 | ④ | M14 | ② |
| M5 | ③ | M15 | ① |
| M6 | ① | M16 | ② |
| M7 | ④ | M17 | ② |
| M8 | ② | M18 | ② |
| M9 | ③ | M19 | ② |
| M10 | ③ | M20 | ④ |
- M1 참조 모니터 = 개념, 보안 커널 = 구현, TCB = 보호 메커니즘 전체.
- M2 C2(통제된 접근 보호)부터 감사·개별 책임. C1은 DAC 수준.
- M3 제품 유형별·구현 독립 = PP. ST는 특정 제품의 구현 종속 명세.
- M4 방향이 거꾸로. gets가 취약, fgets가 대체.
- M5 카나리. ASLR은 주소 랜덤, NX는 실행 금지, RELRO는 GOT 보호.
- M6 ROP. NOP sled는 쉘코드 위치 오차 흡수용.
- M7
%n은 쓰기,%x·%s는 읽기. - M8 TOCTOU형 레이스 컨디션. 대응 mkstemp.
- M9 트로이목마는 위장하지만 복제하지 않는다.
- M10 3세대 은폐형(스텔스). 암호형은 몸체 암호화.
- M11 워터링 홀. 파밍은 DNS·hosts 변조.
- M12 정적 분석. 나머지는 모두 실행이 필요.
- M13 PermitRootLogin no. ③ yes는 암호 인증 허용, 무관.
- M14 둘 다 매칭 안 되면 허용. 그래서 deny에 ALL:ALL을 둔다.
- M15 디렉터리 777 − 077 = 700. 파일이면 600.
- M16 -sS(SYN, Half-open). -sT는 완전 연결.
- M17 RestrictAnonymous. AutoShare는 기본 공유, NoLMHash는 LM 해시, UseLogonCredential은 WDigest.
- M18 Pass-the-Hash. 레인보우 테이블은 해시를 평문으로 되돌리는(조회) 공격.
- M19 Namespace. cgroups는 자원 사용량 제한.
- M20 IMDSv2는 메타데이터 탈취를 어렵게 하는 것이지 앱의 SSRF 취약점 자체를 없애지 않는다. 입력 검증이 따로 필요.